Wiki source code of Architecture

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

Show last authors
1 The MCP server is four thin layers riding existing XWiki infrastructure, plus an extension point for custom tools.
2
3 == Module layout ==
4
5 {{code}}
6 application-ai-llm-mcp/
7 ├── application-ai-llm-mcp-api/ MCPTool @Role (the extension point),
8 │ MCPToolSupport, the public access doors
9 ├── application-ai-llm-mcp-server/ endpoint, manager, config reader,
10 │ access-door implementations, space
11 │ filter, 18 bundled tools, the shared
12 │ tool seams (internal)
13 └── application-ai-llm-mcp-ui/ admin UI + config pages (XAR)
14 {{/code}}
15
16
17 The server module has no dependency on the index/RAG stack. It is installable standalone. Bundled tools query XWiki's built-in Solr index.
18
19 == Four-layer architecture ==
20
21 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.
22
23 {{plantuml}}
24 @startuml
25 !theme bluegray
26 skinparam componentStyle rectangle
27
28 actor "AI agent" as AGENT
29 component "**DefaultMCPResource**\n/rest/wikis/{wiki}/aiLLM/mcp\nidentity and routing" as RES
30 component "**XWikiMCPServerManager**\none SDK server per wiki, built lazily\nlifecycle and middleware" as MGR
31 component "**MCPTool** components\ncomponent hint = tool id\nthe capabilities" as TOOLS
32 component "**Access doors**\nMCPDocumentAccess · MCPWikiReach\nMCPSpaceFilter · MCPDocumentSearch\nshared authorization" as DOORS
33 database "XWiki documents\nand the built-in Solr index" as XWIKI
34 component "**MCPServerConfiguration**\none AI.MCP.Code.MCPServerConfig per wiki" as CONF
35 component "**MCPConfigChangeEventListener**" as EVL
36
37 AGENT --> RES : JSON-RPC over HTTP POST
38 RES --> MGR : the target wiki, set on the context
39 MGR --> TOOLS : executeWrapped, on the request thread
40 TOOLS --> DOORS : every reference, every query
41 DOORS --> XWIKI : as the authenticated user
42 CONF ..> RES : enable gate
43 CONF ..> MGR : which tools are registered
44 CONF ..> DOORS : space filter, cross-wiki reach
45 CONF ..> EVL : on save
46 EVL ..> MGR : invalidates the cached server
47 @enduml
48 {{/plantuml}}
49
50 What each layer is responsible for:
51
52 * **Identity and routing** — {{code}}DefaultMCPResource{{/code}} 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 {{code}}XWikiContext{{/code}}.
53 * **Lifecycle and middleware** — {{code}}XWikiMCPServerManager{{/code}} keeps one SDK server per wiki, built lazily and cached, registers only that wiki's enabled {{code}}MCPTool{{/code}} components on it, and routes every call through {{code}}executeWrapped(){{/code}}, which audits it and normalizes the exceptions it throws.
54 * **The capabilities** — the tools themselves: 18 bundled ones in four categories (Help, Search and Navigation, Structured Data, Authoring), of which {{code}}list_wikis{{/code}} is reach-gated, plus {{code}}list_collections{{/code}} and {{code}}search_collections{{/code}} contributed by the index module when it is installed. The full list is on [[MCP Tool API>>doc:documentation.extensions.dev.llm.mcp-server.mcp-tool-api.WebHome]].
55 * **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.
56
57 == Design principles ==
58
59 Every hard problem is delegated to something XWiki already has:
60
61 * Authentication rides the existing filter chain (OIDC bridge).
62 * Authorization rides {{code}}SecureQuery{{/code}} and {{code}}ContextualAuthorizationManager{{/code}}.
63 * Save attribution rides {{code}}com.xpn.xwiki.api.Document{{/code}}.
64 * Extensibility rides the component manager.
65 * Configuration rides a per-wiki wiki document plus an event listener.
66
67 == Request lifecycle ==
68
69 1. HTTP request arrives at {{code}}DefaultMCPResource{{/code}} ({{code}}/rest/wikis/{wiki}/aiLLM/mcp{{/code}}).
70 1. Enable gate: disabled wiki returns 404 before anything else.
71 1. Authentication has already happened (filter chain). Guest + OIDC → 401.
72 1. Resource sets the target wiki on the XWikiContext and calls {{code}}XWikiMCPServerManager.handleRequest(){{/code}}.
73 1. Manager resolves the wiki's cached SDK server (built lazily, one per wiki).
74 1. SDK parses the JSON-RPC message and dispatches {{code}}tools/call{{/code}} to the registered handler.
75 1. Handler is the middleware ({{code}}executeWrapped{{/code}}), which invokes the tool's {{code}}execute(){{/code}} synchronously on the request thread.
76 1. Result serialized back as HTTP response.
77
78 == Threading ==
79
80 Tool handlers run inline on the HTTP request thread, where XWiki's thread-locals (current user, wiki) natively live. The SDK builder sets {{code}}immediateExecution(true){{/code}} to prevent offloading to Reactor worker threads.
81
82 == Server lifecycle ==
83
84 * {{code}}XWikiMCPServerManager{{/code}} owns a {{code}}ConcurrentHashMap{{/code}} of SDK servers, one per wiki.
85 * {{code}}buildServer(wikiId){{/code}}: reads config, enumerates {{code}}MCPTool{{/code}} components, filters by enabled tool ids, registers each on a fresh transport.
86 * Registration is fault-isolated per tool: a throwing tool is skipped with a WARN.
87 * Invalidation is event-driven: {{code}}MCPConfigChangeEventListener{{/code}} watches saves of {{code}}AI.MCP.Code.MCPServerConfig{{/code}}. Main wiki saves invalidate all servers (cross-wiki reach may have changed); other wiki saves invalidate only that wiki.
88
89 == Shared tool seams ==
90
91 Mechanics that several tools must implement identically live in exactly one place each, so the tools cannot drift apart on them: {{code}}MCPSourceText{{/code}} in the api module (line-ending normalization, line numbering, the output budget), and in the server module's internal tool package {{code}}MCPContentWindow{{/code}} (the range-read window grammar), {{code}}MCPTranslationSupport{{/code}} (exact-match locale resolution), {{code}}MCPWriteSupport{{/code}} (write rights, the {{code}}[AI]{{/code}} version comment, the {{code}}base_version{{/code}} conflict messages), {{code}}MCPTextGuards{{/code}} (neutralizing echoed wiki-authored text), and {{code}}MCPAttachmentSupport{{/code}}, {{code}}MCPHistorySupport{{/code}} and {{code}}MCPLinksSupport{{/code}}.
92
93 == Farm administration ==
94
95 The main wiki's MCP admin section is scripted through {{code}}MCPFarmScriptService{{/code}} ({{code}}$services.mcp{{/code}}), which reads and applies the per-wiki enable and cross-wiki reach flags across the farm.
96
97 == MCP SDK ==
98
99 Version 2.0.0 of {{code}}io.modelcontextprotocol.sdk:mcp-core{{/code}}. The version is owned by the {{code}}mcp-bom{{/code}} import in the root POM. Two SDK defaults are overridden:
100
101 * {{code}}immediateExecution(true){{/code}} — tools run on the request thread, not Reactor workers.
102 * {{code}}validateToolInputs(false){{/code}} — the MCPToolSupport declarative parameter layer is the designed validation gate.

Get Connected