get-file
Retrieve file metadata (uploader, timestamp, size, MIME type) and download URLs for thumbnail, preview, and original. Automatically adds the File: prefix if missing.
Instructions
Returns metadata for a file (uploader, timestamp, size, MIME type) along with download URLs for the thumbnail, preview, and original. The File: prefix is added automatically if omitted.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | File title (with or without the "File:" prefix) |
Implementation Reference
- src/tools/get-file.ts:26-64 (handler)The `handle` function that executes the get-file tool logic. It queries the MediaWiki API for imageinfo (url, size, mime, timestamp, user) of the given file title, normalizes the title with a 'File:' prefix if needed, and returns metadata including thumbnailUrl, descriptionUrl, and original URL.
async handle({ title }, ctx: ToolContext): Promise<CallToolResult> { const mwn = await ctx.mwn(); const fileTitle = title.startsWith('File:') ? title : `File:${title}`; const response = await mwn.request({ action: 'query', titles: fileTitle, prop: 'imageinfo', iiprop: 'url|size|mime|timestamp|user', iiurlwidth: 200, formatversion: '2', }); // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- mwn API response shape; trusted at this boundary const page = response.query?.pages?.[0] as ApiPage | undefined; if (!page || page.missing) { return ctx.format.notFound(`File "${title}" not found`); } const info: ImageInfo | undefined = page.imageinfo?.[0]; if (!info) { return ctx.format.notFound(`No file info available for "${title}"`); } return ctx.format.ok({ title: page.title, descriptionUrl: info.descriptionurl, timestamp: info.timestamp, user: info.user, size: info.size, mime: info.mime, url: info.url, thumbnailUrl: (info as ImageInfo & { thumburl?: string }).thumburl, }); }, }; - src/tools/get-file.ts:7-10 (schema)Zod input schema for get-file: requires a single string parameter `title` (the file title, with or without the 'File:' prefix).
const inputSchema = { title: z.string().describe('File title (with or without the "File:" prefix)'), } as const; - src/tools/get-file.ts:11-64 (registration)The full tool definition object: name 'get-file', description, inputSchema, annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), failureVerb, and target extractor.
export const getFile: Tool<typeof inputSchema> = { name: 'get-file', description: 'Returns metadata for a file (uploader, timestamp, size, MIME type) along with download URLs for the thumbnail, preview, and original. The File: prefix is added automatically if omitted.', inputSchema, annotations: { title: 'Get file', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, } as ToolAnnotations, failureVerb: 'retrieve file data', target: (a) => a.title, async handle({ title }, ctx: ToolContext): Promise<CallToolResult> { const mwn = await ctx.mwn(); const fileTitle = title.startsWith('File:') ? title : `File:${title}`; const response = await mwn.request({ action: 'query', titles: fileTitle, prop: 'imageinfo', iiprop: 'url|size|mime|timestamp|user', iiurlwidth: 200, formatversion: '2', }); // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- mwn API response shape; trusted at this boundary const page = response.query?.pages?.[0] as ApiPage | undefined; if (!page || page.missing) { return ctx.format.notFound(`File "${title}" not found`); } const info: ImageInfo | undefined = page.imageinfo?.[0]; if (!info) { return ctx.format.notFound(`No file info available for "${title}"`); } return ctx.format.ok({ title: page.title, descriptionUrl: info.descriptionurl, timestamp: info.timestamp, user: info.user, size: info.size, mime: info.mime, url: info.url, thumbnailUrl: (info as ImageInfo & { thumburl?: string }).thumburl, }); }, }; - src/tools/index.ts:69-112 (registration)The `registerAllTools` function that registers all tools (including get-file) with the MCP server via the `register()` helper. get-file is included in the `standardTools` array at line 51 and gets dispatched and registered in the registration loop at line 83.
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 (registration)The `register()` helper function that binds a tool's name, description, inputSchema, and annotations to the MCP server's `registerTool()` method.
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>, ); }