Create a New MCP Tool
Steps
Implement a custom MCP tool as an XWiki component. Your module needs the application-ai-llm-mcp-api dependency, which carries the MCPTool role, the MCPToolSupport parameter builder and the access doors, plus mcp-core for the MCP SDK types and xwiki-commons-component-api for the component framework.
- Create the component class, implementing
org.xwiki.contrib.llm.mcp.MCPTool.@Component @Named("my_tool") @Singleton public class MyTool implements MCPTool { @Override public McpSchema.Tool getToolDefinition() { // Return tool name, description, and input JSON schema } @Override public McpSchema.CallToolResult execute(McpSchema.CallToolRequest request) { // Implement the tool logic } } - Declare the component in
src/main/resources/META-INF/components.txt, which is hand-maintained: a component missing from it does not exist at runtime.com.example.MyTool - Declare the parameters once, with
MCPToolSupport.builder(). It produces both the advertised MCP input schema and the typed argument accessors, so schema and parsing cannot drift apart.private static final MCPToolSupport PARAMS = MCPToolSupport.builder() .requiredString("query", "The text to search for.") .integer("limit", "Maximum number of results (default 10).") .build();Build the advertised definition from that same object, so the schema is never written out a second time:
@Override public McpSchema.Tool getToolDefinition() { return McpSchema.Tool.builder(TOOL_ID, PARAMS.inputSchema()) .description("Does something useful.") .build(); }Where the advertised schema varies with cross-wiki reach, hold both variants in
MCPReachAwareParamsand advertise the applicable one: parsing always uses the superset, only the advertised schema differs. - Enforce authorization through
MCPDocumentAccessbefore loading any document, rather than resolving the reference yourself.@Inject private MCPDocumentAccess documentAccess; // Before any operation: documentAccess.resolveAndAuthorize(reference, Right.VIEW);Where a tool does not operate on documents, check wiki-level access with the platform's
ContextualAuthorizationManager. - Return actionable results, using
isErrorresults whose message names the corrective action.return MCPToolSupport.errorResult("Error: 'offset' must be a non-negative integer."); return MCPToolSupport.result("Found: " + count + " results."); - Set the tool metadata that the
mancatalog is built from.@Override public String getCategory() { return "Search & Navigation"; } @Override public String getSummary() { return "A one-line summary for the man catalog."; } @Override public String getManPage() { return """ EXAMPLES Query the wiki for documentation: my_tool query="API reference" """; } - Install your extension in XWiki, then ask a connected agent to call
man: the tool is discovered and registered on the next request, with no restart, and appears in the catalog under its category.Search & Navigation my_tool A one-line summary for the man catalog.
FAQ
Can my tool be disabled by the administrator?
Yes. Per-wiki visibility goes through the enabledTools configuration list, which your tool id must match to be registered on that wiki, and isEnabled() is a global kill switch you can override. Override isWrite() to return true where your tool modifies content: write tools are off by default per wiki.