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 MCPReachAwareParams and advertise the applicable one: parsing always uses the superset, only the advertised schema differs.
- Enforce authorization through MCPDocumentAccess before 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 isError results 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 man catalog 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.