Search Minecraft mappings (live, via linkie)
mc_mappings_searchSearch class, method, or field names across any Minecraft version and mappings namespace. Uses live full-text search from linkie's database.
Instructions
Live full-text search against linkie's mappings database. Returns class/method/field results for ANY (namespace, version) combination linkie carries — no curation gap, no stale snapshot. Use this whenever the user asks 'what is X called in ?' or 'find all methods named foo in 1.21.11 yarn'. For 26.1.x, linkie currently 500s on the mojang_raw namespace — use mc_mojang_mappings instead for those versions.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Class/method/field name (or substring) to search for | |
| namespace | Yes | Mappings namespace. yarn/quilt-mappings for Fabric, mojang for NeoForge, mojang_raw for Mojang's shipped names, mcp/legacy-yarn/feather for 1.8.x, etc. | |
| version | Yes | Minecraft version id, e.g. '1.21.11', '1.8.9', '26.1.2' | |
| type | No | Filter by entry type. Default all. | |
| limit | No | Max hits. Default 25. |
Implementation Reference
- src/index.ts:681-757 (registration)Registration of the 'mc_mappings_search' tool with server.registerTool, including its inputSchema (query, namespace, version, type, limit) and the handler function that calls linkieSearch to perform full-text search against linkie's mappings API and formats results.
server.registerTool( "mc_mappings_search", { title: "Search Minecraft mappings (live, via linkie)", description: "Live full-text search against linkie's mappings database. Returns " + "class/method/field results for ANY (namespace, version) combination " + "linkie carries — no curation gap, no stale snapshot. Use this " + "whenever the user asks 'what is X called in <specific version>?' or " + "'find all methods named foo in 1.21.11 yarn'. For 26.1.x, linkie " + "currently 500s on the mojang_raw namespace — use mc_mojang_mappings " + "instead for those versions.", inputSchema: { query: z.string().describe("Class/method/field name (or substring) to search for"), namespace: LinkieNamespaceSchema.describe( "Mappings namespace. yarn/quilt-mappings for Fabric, mojang for NeoForge, " + "mojang_raw for Mojang's shipped names, mcp/legacy-yarn/feather for 1.8.x, etc.", ), version: z.string().describe("Minecraft version id, e.g. '1.21.11', '1.8.9', '26.1.2'"), type: z.enum(["class", "method", "field", "all"]).optional().describe("Filter by entry type. Default all."), limit: z.number().int().positive().max(100).optional().describe("Max hits. Default 25."), }, }, async ({ query, namespace, version, type, limit }) => { let hits: LinkieHit[]; try { hits = await linkieSearch({ namespace, version, query, type, limit }); } catch (err) { if (err instanceof LinkieNotIngestedError) { const isPost1x = /^26\./.test(err.version); const fallback = isPost1x ? `**Note**: linkie's mojang_raw can't load 26.x because Mojang stopped shipping client_mappings.txt. ` + `Calling mc_mojang_mappings will return the same dead-end. ` + `Workaround: mc_list_versions to find a namespace that *has* ingested ${err.version}, ` + `or use mc_lookup_class for stable concept-level translations.` : `Try mc_mojang_mappings(version="${err.version}", query="${query}") for the Mojang official names.`; return text( `linkie advertises ${err.namespace}/${err.version} but its search backend ` + `hasn't ingested it yet:\n\n ${err.detail}\n\n${fallback}`, ); } return text(`Search failed: ${(err as Error).message}`); } if (hits.length === 0) { return text( `No hits for "${query}" in ${namespace}/${version}. ` + `Check the version exists in this namespace via mc_list_versions.`, ); } const lines: string[] = [ `# ${hits.length} hit${hits.length === 1 ? "" : "s"} in ${namespace}/${version} for "${query}"`, "", ]; for (const h of hits) { if (h.type === "class") { lines.push(`- **class** \`${h.mapped}\``); if (h.intermediary && h.intermediary !== h.mapped) lines.push(` intermediary: \`${h.intermediary}\``); if (h.obfuscated) lines.push(` obfuscated: \`${h.obfuscated}\``); } else { const decoded = h.descriptor ? h.type === "method" ? decodeMethodDescriptor(h.descriptor) : decodeFieldDescriptor(h.descriptor) : null; const sigBits = [ decoded ? `\`${decoded}\`` : null, h.params && h.params.length ? `param names \`(${h.params.join(", ")})\`` : null, ].filter(Boolean); lines.push(`- **${h.type}** \`${h.owner ?? "?"}#${h.mapped}\`${sigBits.length ? " " + sigBits.join(" · ") : ""}`); if (h.descriptor) lines.push(` raw descriptor: \`${h.descriptor}\``); if (h.intermediary && h.intermediary !== h.mapped) lines.push(` intermediary: \`${h.intermediary}\``); if (h.obfuscated) lines.push(` obfuscated: \`${h.obfuscated}\``); } } return text(lines.join("\n")); }, ); - src/linkie.ts:105-180 (helper)The linkieSearch function (exported as 'search') that performs the actual HTTP request to the linkie API, parses the response, and returns structured LinkieHit objects. This is the core helper invoked by the mc_mappings_search handler.
/** Search linkie. Returns structured hits or throws on transport errors. */ export async function search(opts: { namespace: string; version: string; query: string; limit?: number; /** Filter to one of class/method/field; "all" by default. */ type?: "class" | "method" | "field" | "all"; /** Allow fuzzy results. */ allowFuzzy?: boolean; }): Promise<LinkieHit[]> { const { namespace, version, query } = opts; const limit = opts.limit ?? 25; const cacheKey = `${namespace}|${version}|${query}|${opts.type ?? "all"}|${limit}|${opts.allowFuzzy ? 1 : 0}`; // 1-hour TTL for search results — same query + version is stable for hours // at a time. The model retries the same lookups across turns. const data = await cached<LinkieSearchResponse | { _notIngested: { namespace: string; version: string; detail: string } }>( "linkie-search", cacheKey, 60 * 60 * 1000, async () => { const url = new URL(`${LINKIE_API_BASE}/api/search`); url.searchParams.set("namespace", namespace); url.searchParams.set("version", version); url.searchParams.set("query", query); url.searchParams.set("limit", String(limit)); if (opts.allowFuzzy) url.searchParams.set("allowFuzzy", "true"); const res = await fetch(url); if (!res.ok) { const body = await res.text(); if (res.status === 500 && /Failed to load/.test(body)) { // Cache the not-ingested response — it stays not-ingested until linkie // does a backend refresh, no point pinging again every minute. return { _notIngested: { namespace, version, detail: body.trim() } }; } throw new Error(`linkie /api/search: HTTP ${res.status} — ${body.slice(0, 160)}`); } return (await res.json()) as LinkieSearchResponse; }, ); if ("_notIngested" in data) { throw new LinkieNotIngestedError(data._notIngested.namespace, data._notIngested.version, data._notIngested.detail); } const filterT = opts.type === "class" ? "c" : opts.type === "method" ? "m" : opts.type === "field" ? "f" : null; const hits: LinkieHit[] = []; for (const e of data.entries) { if (filterT && e.t !== filterT) continue; if (e.t === "c") { hits.push({ type: "class", score: e.z, mapped: dotted(e.n ?? e.i ?? e.o ?? "?"), intermediary: e.i ? dotted(e.i) : undefined, obfuscated: e.o ? dotted(e.o) : undefined, }); } else { hits.push({ type: e.t === "m" ? "method" : "field", score: e.z, mapped: e.n ?? e.i ?? e.o ?? "?", intermediary: e.i, obfuscated: e.o, owner: e.c ? dotted(e.c) : e.b ? dotted(e.b) : e.a ? dotted(e.a) : undefined, descriptor: e.f ?? e.e ?? e.d, params: e.p ? Object.keys(e.p).sort((x, y) => Number(x) - Number(y)).map((k) => e.p![k]) : undefined, }); } } hits.sort((a, b) => b.score - a.score); return hits; } - src/linkie.ts:51-66 (schema)The LinkieHit interface definition, which is the return type schema used by the mc_mappings_search tool handler to format search results.
export interface LinkieHit { type: "class" | "method" | "field"; score: number; /** Mapped (named) form — what the user reads. */ mapped: string; /** Intermediary (Yarn intermediary or hashed) form — runtime-stable. */ intermediary?: string; /** Obfuscated form. */ obfuscated?: string; /** For method/field: owner class FQN (mapped). */ owner?: string; /** Method/field descriptor in mapped form. */ descriptor?: string; /** Method parameter names (mapped). */ params?: string[]; } - src/linkie.ts:68-71 (schema)The LinkieNamespace interface used in the tool's input validation (namespace + version list).
export interface LinkieNamespace { id: string; versions: { version: string; stable: boolean }[]; } - src/index.ts:80-93 (schema)The LinkieNamespaceSchema (z.enum) used for input validation of the 'namespace' parameter in mc_mappings_search and other tools.
const LinkieNamespaceSchema = z.enum([ "yarn", "mojang", "mojang_raw", "mojang_hashed", "mojang_srg", "quilt-mappings", "mcp", "legacy-yarn", "yarrn", "plasma", "barn", "feather", ]);