Wiki source code of Create a New MCP Tool

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

Show last authors
1 Implement a custom MCP tool as an XWiki component. Your module needs the {{code}}application-ai-llm-mcp-api{{/code}} dependency, which carries the {{code}}MCPTool{{/code}} role, the {{code}}MCPToolSupport{{/code}} parameter builder and the [[access doors>>doc:documentation.extensions.dev.llm.mcp-server.access-doors.WebHome]], plus {{code}}mcp-core{{/code}} for the MCP SDK types and {{code}}xwiki-commons-component-api{{/code}} for the component framework.
2
3 1. Create the component class, implementing {{code}}org.xwiki.contrib.llm.mcp.MCPTool{{/code}}.(((
4 {{code language="java"}}
5 @Component
6 @Named("my_tool")
7 @Singleton
8 public class MyTool implements MCPTool
9 {
10 @Override
11 public McpSchema.Tool getToolDefinition()
12 {
13 // Return tool name, description, and input JSON schema
14 }
15
16 @Override
17 public McpSchema.CallToolResult execute(McpSchema.CallToolRequest request)
18 {
19 // Implement the tool logic
20 }
21 }
22 {{/code}}
23 )))
24 1. Declare the component in {{code}}src/main/resources/META-INF/components.txt{{/code}}, which is hand-maintained: a component missing from it does not exist at runtime.(((
25 {{code}}
26 com.example.MyTool
27 {{/code}}
28 )))
29 1. Declare the parameters once, with {{code}}MCPToolSupport.builder(){{/code}}. It produces both the advertised MCP input schema and the typed argument accessors, so schema and parsing cannot drift apart.(((
30 {{code language="java"}}
31 private static final MCPToolSupport PARAMS = MCPToolSupport.builder()
32 .requiredString("query", "The text to search for.")
33 .integer("limit", "Maximum number of results (default 10).")
34 .build();
35 {{/code}}
36
37 Build the advertised definition from that same object, so the schema is never written out a second time:
38
39 {{code language="java"}}
40 @Override
41 public McpSchema.Tool getToolDefinition()
42 {
43 return McpSchema.Tool.builder(TOOL_ID, PARAMS.inputSchema())
44 .description("Does something useful.")
45 .build();
46 }
47 {{/code}}
48
49 Where the advertised schema varies with cross-wiki reach, hold both variants in {{code}}MCPReachAwareParams{{/code}} and advertise the applicable one: parsing always uses the superset, only the advertised schema differs.
50 )))
51 1. Enforce authorization through {{code}}MCPDocumentAccess{{/code}} before loading any document, rather than resolving the reference yourself.(((
52 {{code language="java"}}
53 @Inject
54 private MCPDocumentAccess documentAccess;
55
56 // Before any operation:
57 documentAccess.resolveAndAuthorize(reference, Right.VIEW);
58 {{/code}}
59
60 Where a tool does not operate on documents, check wiki-level access with the platform's {{code}}ContextualAuthorizationManager{{/code}}.
61 )))
62 1. Return actionable results, using {{code}}isError{{/code}} results whose message names the corrective action.(((
63 {{code language="java"}}
64 return MCPToolSupport.errorResult("Error: 'offset' must be a non-negative integer.");
65 return MCPToolSupport.result("Found: " + count + " results.");
66 {{/code}}
67 )))
68 1. Set the tool metadata that the {{code}}man{{/code}} catalog is built from.(((
69 {{code language="java"}}
70 @Override
71 public String getCategory()
72 {
73 return "Search & Navigation";
74 }
75
76 @Override
77 public String getSummary()
78 {
79 return "A one-line summary for the man catalog.";
80 }
81
82 @Override
83 public String getManPage()
84 {
85 return """
86 EXAMPLES
87 Query the wiki for documentation:
88 my_tool query="API reference"
89 """;
90 }
91 {{/code}}
92 )))
93 1. Install your extension in XWiki, then ask a connected agent to call {{code}}man{{/code}}: the tool is discovered and registered on the next request, with no restart, and appears in the catalog under its category.(((
94 {{code}}
95 Search & Navigation
96 my_tool A one-line summary for the man catalog.
97 {{/code}}
98 )))

Get Connected