list_extensions
Retrieve available WooCommerce extensions for testing with QIT. Filter results by name or slug to manage response size.
Instructions
List WooCommerce extensions you have access to test with QIT. Use 'search' parameter to filter results and reduce response size.
⚠️ QIT CLI not detected. QIT CLI not found. Please install it using one of these methods:
Via Composer (recommended): composer require woocommerce/qit-cli --dev
Set QIT_CLI_PATH environment variable: export QIT_CLI_PATH=/path/to/qit
Ensure 'qit' is available in your system PATH
For more information, visit: https://github.com/woocommerce/qit-cli
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| search | No | Search/filter extensions by name or slug (recommended to reduce response size) | |
| limit | No | Maximum number of extensions to return (default: 20, use higher values only when needed) |
Implementation Reference
- src/tools/utilities.ts:19-76 (handler)The async handler function that implements the core logic of the 'list_extensions' tool: executes QIT CLI command, parses tabular output into structured extensions list, applies filtering and limiting, and formats a user-friendly text response.handler: async (args: { search?: string; limit?: number }) => { const result = await executeQitCommand(["extensions", "--no-interaction"]); if (!result.success) { return { content: result.stderr || result.stdout || "Failed to list extensions", isError: true, }; } // Parse table output format: | ID | Slug | Type | const lines = result.stdout.split("\n"); let extensions: Array<{ id: string; slug: string; type: string }> = []; for (const line of lines) { // Skip header, separator lines, and empty lines if (!line.startsWith("|") || line.includes("---") || line.includes(" ID ")) { continue; } const parts = line.split("|").map(p => p.trim()).filter(p => p); if (parts.length >= 3) { extensions.push({ id: parts[0], slug: parts[1], type: parts[2], }); } } const totalCount = extensions.length; // Filter by search term if provided if (args.search) { const searchLower = args.search.toLowerCase(); extensions = extensions.filter(ext => ext.slug.toLowerCase().includes(searchLower) ); } // Apply limit (default 20 to prevent huge responses) const limit = args.limit ?? 20; const limited = extensions.slice(0, limit); const hasMore = extensions.length > limit; // Text format - compact representation const outputLines = limited.map(ext => `- ${ext.slug} (${ext.type})`); let output = `Extensions (showing ${limited.length} of ${extensions.length}`; if (args.search) output += ` matching "${args.search}"`; output += `, ${totalCount} total):\n${outputLines.join("\n")}`; if (hasMore) { output += `\n\n... and ${extensions.length - limit} more. Use 'limit' parameter to see more or 'search' to filter.`; } return { content: output, isError: false }; },
- src/tools/utilities.ts:6-18 (schema)Tool name, description, and Zod input schema defining optional parameters: 'search' (string for filtering) and 'limit' (number for max results).name: "list_extensions", description: "List WooCommerce extensions you have access to test with QIT. Use 'search' parameter to filter results and reduce response size.", inputSchema: z.object({ search: z .string() .optional() .describe("Search/filter extensions by name or slug (recommended to reduce response size)"), limit: z .number() .optional() .describe("Maximum number of extensions to return (default: 20, use higher values only when needed)"), }),
- src/tools/index.ts:10-19 (registration)Aggregates all tool modules into a single 'allTools' object by spreading 'utilitiesTools' (which contains 'list_extensions') along with other tool sets; this object is imported and used by the MCP server for tool listing and execution.export const allTools = { ...authTools, ...testExecutionTools, ...testResultsTools, ...groupsTools, ...environmentTools, ...packagesTools, ...configTools, ...utilitiesTools, };
- src/server.ts:24-87 (registration)MCP server request handlers for listing tools (using Object.entries(allTools)) and calling tools (lookup by name in allTools, validate inputSchema, invoke handler); this registers 'list_extensions' with the Model Context Protocol server.// List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { // Check if QIT CLI is available const cliInfo = detectQitCli(); const tools = Object.entries(allTools).map(([_, tool]) => ({ name: tool.name, description: cliInfo ? tool.description : `${tool.description}\n\n⚠️ QIT CLI not detected. ${getQitCliNotFoundError()}`, inputSchema: zodToJsonSchema(tool.inputSchema), })); return { tools }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; const tool = allTools[name as ToolName]; if (!tool) { return { content: [ { type: "text", text: `Unknown tool: ${name}`, }, ], isError: true, }; } try { // Validate input const validatedArgs = tool.inputSchema.parse(args); // Execute tool // eslint-disable-next-line @typescript-eslint/no-explicit-any const result = await (tool.handler as (args: any) => Promise<{ content: string; isError: boolean }>)(validatedArgs); return { content: [ { type: "text", text: result.content, }, ], isError: result.isError, }; } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [ { type: "text", text: `Error: ${message}`, }, ], isError: true, }; } });