Skip to main content
Glama

search_cases

Search Australian case law using queries with neutral citation fallbacks. Retrieve structured results with citation metadata and jurisdiction filtering.

Instructions

Search Australian case law with neutral citation fallbacks.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
formatNojson
jurisdictionNo
limitNo
queryYes

Implementation Reference

  • src/index.ts:63-82 (registration)
    Registers the 'search_cases' MCP tool, specifying title, description, input schema, and handler function that delegates to searchAustLii and formatter.
    server.registerTool( "search_cases", { title: "Search Cases", description: "Search Australian case law with neutral citation fallbacks. Supports 'auto' (default), 'relevance', or 'date' sorting. Auto mode intelligently detects case name queries (e.g., 'X v Y') and uses relevance sorting to find the specific case, while using date sorting for topic searches.", inputSchema: searchCasesShape, }, async (rawInput) => { const { query, jurisdiction, limit, format, sortBy } = searchCasesParser.parse(rawInput); const results = await searchAustLii(query, { type: "case", jurisdiction, limit, sortBy, }); return formatSearchResults(results, format ?? "json"); }, );
  • Zod input schema definition for the search_cases tool (query required, optional jurisdiction, limit, format, sortBy).
    const searchCasesShape = { query: z.string().min(1, "Query cannot be empty."), jurisdiction: jurisdictionEnum.optional(), limit: z.number().int().min(1).max(50).optional(), format: formatEnum.optional(), sortBy: sortByEnum.optional(), }; const searchCasesParser = z.object(searchCasesShape);
  • Inline handler function for search_cases tool: validates input, invokes searchAustLii with case type, formats and returns results.
    async (rawInput) => { const { query, jurisdiction, limit, format, sortBy } = searchCasesParser.parse(rawInput); const results = await searchAustLii(query, { type: "case", jurisdiction, limit, sortBy, }); return formatSearchResults(results, format ?? "json"); },
  • Main searchAustLii helper function: builds AustLII search URL, fetches and parses HTML results, filters by type (case/legislation), extracts metadata, applies smart sorting/boosting.
    export async function searchAustLii( query: string, options: SearchOptions, ): Promise<SearchResult[]> { try { const searchParams = buildSearchParams(query, options); const limit = options.limit ?? 10; // Determine sort mode (auto-detect or use explicit setting) const sortMode = determineSortMode(query, options); const searchUrl = new URL(AUSTLII_SEARCH_BASE); searchUrl.searchParams.set("method", "boolean"); searchUrl.searchParams.set("query", searchParams.query); searchUrl.searchParams.set("meta", searchParams.meta); searchUrl.searchParams.set("results", String(limit)); // Set sort order based on mode if (sortMode === "relevance") { searchUrl.searchParams.set("view", "relevance"); } else { searchUrl.searchParams.set("view", "date"); } const response = await axios.get(searchUrl.toString(), { headers: { "User-Agent": "auslaw-mcp/0.1.0 (legal research tool)", }, timeout: 15000, }); const html = response.data; const $ = cheerio.load(html); const results: SearchResult[] = []; // Parse search results - AustLII returns results in an <OL> ordered list $("ol li").each((_, element) => { const $li = $(element); const $link = $li.find("a").first(); const title = $link.text().trim(); let url = $link.attr("href") || ""; // Make URL absolute if relative if (url && !url.startsWith("http")) { url = `http://classic.austlii.edu.au${url}`; } if (title && url) { // Always skip journal articles - we only want primary sources if (url.includes("/journals/")) { return; // Skip journal articles } // For cases, only include actual case databases if (options.type === "case" && !url.includes("/cases/")) { return; // Skip non-case results } // For legislation, only include legislation databases if (options.type === "legislation" && !url.includes("/legis/")) { return; // Skip non-legislation results } // Try to extract citation from title const citationMatch = title.match(/\[(\d{4})\]\s*([A-Z]+)\s*(\d+)/); const neutralCitation = citationMatch ? citationMatch[0] : undefined; const year = citationMatch ? citationMatch[1] : undefined; // Extract jurisdiction from URL const jurisdictionMatch = url.match(/\/au\/cases\/(cth|vic|nsw|qld|sa|wa|tas|nt|act)\//i); const jurisdiction = jurisdictionMatch?.[1]?.toLowerCase(); // Extract summary from <small> tag if present const $small = $li.find("small"); const summary = $small.length > 0 ? $small.text().trim() : undefined; results.push({ title, citation: undefined, neutralCitation, url, source: "austlii", summary, jurisdiction, year, type: options.type, }); } }); // Apply title matching boost when using relevance sorting let finalResults = results; if (sortMode === "relevance" && isCaseNameQuery(query)) { finalResults = boostTitleMatches(results, query); } return finalResults.slice(0, limit); } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`AustLII search failed: ${error.message}`); } throw error; } }
  • formatSearchResults helper: converts SearchResult[] to MCP CallToolResult in json, html, markdown, or text formats.
    export function formatSearchResults( results: SearchResult[], format: ResponseFormat, ): CallToolResult { switch (format) { case "json": return { content: ensureContent(JSON.stringify(results, null, 2)), structuredContent: { format: "json", data: results, }, }; case "html": { const rows = results .map((result) => { const citation = result.citation ?? result.neutralCitation ?? ""; const summary = result.summary ? `<p>${escapeHtml(result.summary)}</p>` : ""; return `<li><a href="${escapeHtml(result.url)}">${escapeHtml(result.title)}</a>${ citation ? ` (${escapeHtml(citation)})` : "" }${summary}</li>`; }) .join("\n"); return { content: ensureContent(`<ul>\n${rows}\n</ul>`), }; } case "markdown": { const lines = results.map((result) => { const citation = result.citation ?? result.neutralCitation ?? ""; const summary = result.summary ? ` — ${result.summary}` : ""; return `- [${result.title}](${result.url})${citation ? ` (${citation})` : ""}${summary}`; }); return { content: ensureContent(lines.join("\n")), }; } case "text": default: { const lines = results.map((result, idx) => { const citation = result.citation ?? result.neutralCitation ?? ""; const summary = result.summary ? `\n ${result.summary}` : ""; return `${idx + 1}. ${result.title}${citation ? ` (${citation})` : ""}\n ${result.url}${summary}`; }); return { content: ensureContent(lines.join("\n")), }; } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/russellbrenner/auslaw-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server