search-page-by-prefix
Retrieve wiki page titles that start with a specified prefix, enabling autocomplete and title lookup. Returns up to 500 titles per request.
Instructions
Returns wiki page titles beginning with a given prefix (suited to autocomplete and title lookup). Only titles are returned — no snippets, sizes, or IDs. Accepts up to 500 titles per call (default 10); additional matches beyond the cap are flagged in the response. For full-text content search, use search-page.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| prefix | Yes | Wiki page title prefix | |
| limit | No | Maximum number of results to return | |
| namespace | No | Namespace ID to restrict the search to |
Implementation Reference
- src/tools/search-page-by-prefix.ts:45-83 (handler)The handle function that executes the search-page-by-prefix tool logic. It calls the MediaWiki API 'allpages' list with the given prefix, limit, and optional namespace, then formats the results as page titles, IDs, and namespaces. Detects truncation via the 'continue' field in the API response.
async handle({ prefix, limit, namespace }, ctx: ToolContext): Promise<CallToolResult> { const mwn = await ctx.mwn(); const params: Record<string, string | number | boolean> = { action: 'query', list: 'allpages', apprefix: prefix, formatversion: '2', }; if (limit !== undefined) { params.aplimit = limit; } if (namespace !== undefined) { params.apnamespace = namespace; } const response = await mwn.request(params); const pages: AllPagesEntry[] = response.query?.allpages ?? []; const truncation: TruncationInfo | null = response.continue ? { reason: 'capped-no-continuation', returnedCount: pages.length, limit: limit ?? 10, itemNoun: 'titles', narrowHint: 'narrow the prefix or raise limit (max 500)', } : null; return ctx.format.ok({ results: pages.map((p) => ({ title: p.title, pageId: p.pageid, namespace: p.ns, })), ...(truncation !== null ? { truncation } : {}), }); }, }; - Input schema for the tool: prefix (string, required), limit (number, 1-500, optional, default 10), namespace (non-negative integer, optional). Defined using zod.
const inputSchema = { prefix: z.string().describe('Wiki page title prefix'), limit: z .number() .int() .min(1) .max(500) .optional() .describe('Maximum number of results to return'), namespace: z .number() .int() .nonnegative() .optional() .describe('Namespace ID to restrict the search to'), } as const; - src/tools/search-page-by-prefix.ts:30-84 (registration)The full tool object export including name 'search-page-by-prefix', description, annotations, failureVerb, target extractor, and the handle function.
export const searchPageByPrefix: Tool<typeof inputSchema> = { name: 'search-page-by-prefix', description: 'Returns wiki page titles beginning with a given prefix (suited to autocomplete and title lookup). Only titles are returned — no snippets, sizes, or IDs. Accepts up to 500 titles per call (default 10); additional matches beyond the cap are flagged in the response. For full-text content search, use search-page.', inputSchema, annotations: { title: 'Search page by prefix', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, } as ToolAnnotations, failureVerb: 'retrieve search data', target: (a) => a.prefix, async handle({ prefix, limit, namespace }, ctx: ToolContext): Promise<CallToolResult> { const mwn = await ctx.mwn(); const params: Record<string, string | number | boolean> = { action: 'query', list: 'allpages', apprefix: prefix, formatversion: '2', }; if (limit !== undefined) { params.aplimit = limit; } if (namespace !== undefined) { params.apnamespace = namespace; } const response = await mwn.request(params); const pages: AllPagesEntry[] = response.query?.allpages ?? []; const truncation: TruncationInfo | null = response.continue ? { reason: 'capped-no-continuation', returnedCount: pages.length, limit: limit ?? 10, itemNoun: 'titles', narrowHint: 'narrow the prefix or raise limit (max 500)', } : null; return ctx.format.ok({ results: pages.map((p) => ({ title: p.title, pageId: p.pageid, namespace: p.ns, })), ...(truncation !== null ? { truncation } : {}), }); }, }; - src/tools/index.ts:69-112 (registration)The registerAllTools function that registers searchPageByPrefix (and all other tools) with the MCP server via the register() helper. The tool is included in the standardTools array at line 48.
export function registerAllTools( server: McpServer, reconcile: Reconcile, ctx: ToolContext, ): Map<string, RegisteredTool> { const registered = new Map<string, RegisteredTool>(); // oxlint-disable-next-line typescript/no-explicit-any const allStandardTools: Tool<any>[] = [ ...standardTools, ...extensionPacks.flatMap((p) => p.tools), ]; for (const tool of allStandardTools) { try { registered.set(tool.name, register(server, tool, dispatch(tool, ctx))); } catch (error) { logger.error('Error registering tool', { error: errorMessage(error) }); } } const mgmtCtx: ManagementContext = { ...ctx, reconcile }; for (const tool of managementTools) { try { registered.set(tool.name, register(server, tool, dispatch(tool, mgmtCtx))); } catch (error) { logger.error('Error registering tool', { error: errorMessage(error) }); } } // Extension-gated tools start disabled. They're enabled by reconcile() once // the extension detector confirms the relevant extension is installed on // the active wiki. This avoids a race where tools/list arrives before the // initial reconcile completes. for (const pack of extensionPacks) { for (const tool of pack.tools) { const reg = registered.get(tool.name); if (reg && reg.enabled) { reg.disable(); } } } return registered; } - src/runtime/register.ts:11-31 (helper)The register() helper function that binds a Tool object to an MCP server via server.registerTool(), passing the tool name, description, inputSchema, and annotations.
export function register<TSchema extends ZodRawShape, TCtx extends ToolContext>( server: McpServer, tool: Tool<TSchema, TCtx>, handler: (args: z.infer<z.ZodObject<TSchema>>) => Promise<CallToolResult>, ): RegisteredTool { return server.registerTool( tool.name, { description: tool.description, inputSchema: tool.inputSchema, annotations: tool.annotations, }, // The SDK callback signature is `(args, extra) => ...`. Our descriptor // handlers ignore the `extra` parameter, so we widen the type here. The // `ZodRawShape` constraint from zod is the same shape as the SDK's // `ZodRawShapeCompat` (Record<string, AnySchema>) — TypeScript just // can't unify them through the generic boundary. // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- generic boundary; MCP SDK's ToolCallback can't be unified with our typed handler handler as unknown as ToolCallback<TSchema>, ); }