@cyanheads/courtlistener-mcp-server
This server has a remotely hosted endpoint. Open its connector listing for connection details, authentication requirements, and setup instructions:
Public Hosted Server: https://courtlistener.caseyjhand.com/mcp
Overview
US case law and federal court records from CourtListener's 9M+ opinion corpus and its RECAP mirror of PACER. Search opinions and dockets, trace citation networks, resolve citations, look up judges and courts, and read oral argument transcripts and judicial financial disclosures.
Tools
Tool | Description |
| Full-text search across 9M+ court opinions with field syntax, court, date, and status filters |
| Fetch an opinion cluster's metadata and variant text (majority, concurrence, dissent), with source-completion status |
| Trace a cluster's citation network: opinions it cites ( |
| Resolve every citation in a text (e.g. "410 U.S. 113") to cluster IDs and case metadata |
| Search RECAP federal dockets by case name, party, attorney, court, and filing date |
| Fetch a federal docket's paged entries or selected filings' extracted text |
| Fetch the parties and attorneys of record on a RECAP docket |
| Search judges by name, appointing president, court, and political affiliation |
| Fetch a judge's positions, education, political affiliations, and ABA ratings |
| List courts by jurisdiction type, active/inactive status, and scraper coverage |
| Search appellate oral argument recordings by case name, transcript text, court, and argument date |
| Fetch one oral argument's panel, duration, MP3 link, and speech-to-text transcript |
| Search judicial financial disclosure filings by judge and year |
| Fetch one disclosure's line items with coded values decoded to dollar ranges |
Resources
Resource | Description |
| Jurisdiction codes, common court IDs, search type codes, rate limits, and the maintenance window |
| Research guide for identifier chains, text completion, citation treatment, and coverage limits |
The jurisdiction codes are also listed on the jurisdiction parameter of courtlistener_lookup_courts, for clients that don't surface resources.
Prompts
Prompt | Description |
| Generate a structured legal research plan for a topic or question |
Related MCP server: CourtListener MCP Server
Capability reference
Result-page sizes accept positive integers and bound outgoing requests: 20 for searches/citations, 10 for parties, and 50 for docket entries. Both response surfaces carry page_sizing (requested, bounded, actual, upstream). Upstream search/disclosure pages have a 20-row minimum, parties/entries use fixed 20-row pages, and citing slices cited IDs before searching. Returned pages are preserved; empty/final pages and page-local filters can produce fewer rows. Continue with the native cursor rather than increasing the requested size.
courtlistener_search_opinions tool
qis required and takes CourtListener field syntax (caseName:"roe v wade",court_id:scotus,judge:"Alito") andAND/OR/NOT; filter bycourt,filed_after/filed_before, andstatus, and sort withorder_by(score descdefault,dateFiled desc,dateFiled asc,citeCount desc); 20 results per page, continued withnext_cursorEach result carries
cluster_id(forcourtlistener_get_opinionandcourtlistener_get_citations),docket_id,cite_count, asnippet, andopinions[]variants with opinion ID,type,author_id, andlocal_path;totalCountandeffectiveQueryreport the matchOmit
statusfor CourtListener's Published default, or select one publication status, includingIn-chambersandRelating-to.
courtlistener_get_opinion tool
cluster_idis required; after an outline response,sections: ["opinion_<id>", ...]pulls specific variants, and a name the cluster doesn't have fails asunknown_sectionCluster metadata (case name,
court_id, citations,cite_count,precedential_status, syllabus, posture,docket_id) plus each variant'shtml_text,plain_text,cites[],download_url, andtype_label, the same labelcourtlistener_search_opinionsreportsSmall responses use
kind: "full". Oversized variants or metadata return a boundedoutline, then typedpageresponses throughretrieval.next_cursor; repeat the original ID and selection withcursoruntil null.Supplied
plain_textis preserved; markup-only variants gain readable text with paragraphs, tables, lists, footnotes, and decoded entities.html_textretains raw source and renders as fenced text. Search/citation snippets use the same readable normalization.variants_completionreports whether the bounded source walk finished and its remaining upstream variant cursor.docket_enrichmentdistinguishesnot_linked,resolved,source_fields_absent, andlookup_failedwith a sanitized failure category; cancellation propagates.Primary continuation remains stable when optional docket enrichment changes. Oversized enrichment has its own
enrichment_retrieval.next_cursor, passed asenrichment_cursorwith the same cluster and selection. Keep enrichment chunks only whilesource_idis unchanged; a changed source restarts that stream. A metadata-only partial response can have a null primary cursor while enrichment continues. Legacy v1 cursors retain their original enrichment-sensitive behavior.
courtlistener_get_citations tool
cluster_idis required;directioniscited_by(default, opinions that cite this one) orciting(opinions it cites); optionalcourtandfiled_afterfilters; up to 20 results per page, continued withcursorRows carry
cluster_id,court_id,date_filed,cite_count, andsnippet; forciting, totals count the unfiltered cited-opinion list, and a filtered page can come back empty whilenext_cursoris still set.source_variants_completionandtotal_is_partialqualifyobserved_total; incomplete variants make this a lower bound and omit the exacttotalCounttrailer.For
citing,cursoris a nonnegative safe decimal integer offset (01,+1,1.0, and1.all mean1); malformed offsets fail asinvalid_cursorbefore any request. An offset at or past the end returns an empty page with the source name and unfiltered distinct-opinion total, without searching.cited_bycursors stay opaque.
courtlistener_lookup_citation tool
citationtakes one citation or a passage of up to 64,000 characters, and every citation in it resolves;max_court_lookups(default 4, max 20,0to skip) caps the docket requests spent on court namesOne
matches[]entry per citation, withstatus(200 one case, 300 several candidates, 400 unrecognized reporter, 404 no match, 429 past the per-request citation cap) andstatus_label; each of itsclusters[]carriescluster_id,docket_id,court_id, andcourt_resolution(resolved,no_docket,lookup_failed,over_budget, only the last worth retrying with a larger budget)Unresolved citations come back as entries, not errors; only text with no parseable citation fails, as
not_found. CourtListener meters this endpoint per citation submitted, separately from the per-request limits
courtlistener_search_dockets tool
qis required and matches case name, docket number, party, and attorney names;party_name(ANDed withq),court, andfiled_after/filed_beforenarrow it; 20 results per page, continued withnext_cursorEach docket carries
docket_id,parties,attorneys,firms,suit_nature,assigned_to/referred_to, and up to 3sample_documentswithis_availableand a RECAPfilepath_localURL; every response adds acoverage_noteon RECAP's partial PACER coverage
courtlistener_get_docket tool
docket_idis required; entries come 20 per page (CourtListener ignoresentries_page_size), walked withentries_pageand top-levelnext_cursor. Without a document selection, returns docket metadata andentries[];total_entriesis null when upstream supplies no numeric total.document_idsselects documents from the requested entries page. Selected responses carrykind,selected_documents, source/storage links, and rawplain_text; large records useretrieval.next_cursor, passed ascursorwith the same docket ID, entries page, and selection. Listing-only fields are optional in selected responses.text_statusisavailable,unavailable,not_extracted, orunknown; extracted text can exist independently ofis_available. IDs absent from the page fail asdocument_not_on_page; an entry without a matching docket relation fails asdocument_ownership_unverified. Selection adds no document-detail requests or page walks.
courtlistener_get_parties tool
docket_idis required;cursortakes the opaquenext_cursortoken, not a page number; outgoingpage_sizeis bounded to 10 and CourtListener may not honor itEach party carries
name, its docket-scopedrole, andattorneys[]withname,contact_raw,role_code/role(codes 5–9 mean no longer of record), anddate_action;total_partiesuses the upstream total when supplied, otherwise counts a single-page result or stays nullattorney_resolutionreports resolved, exhausted, or capped lookups, unresolved IDs, and the remaining upstream roster cursor. Resolution stops after five roster pages or when the local request budget blocks a later page; already fetched records are retained. Per-attorneyresolutiondistinguishes a resolved record with empty source fields fromnot_foundafter exhaustion andnot_fetchedafter the cap. Upstream roster/variant cursors describe completeness; these tools do not accept them as new retrieval inputs.
courtlistener_search_judges tool
qis required; filter byappointer(the president's last name),court, andpolitical_affiliation(d,r,i,l,g,u); 20 results per page, continued withnext_cursorResults carry
person_id(forcourtlistener_get_judge),political_affiliationandaba_ratingas labels rather than codes, and acurrent_position: the one with no termination date, or the latest-starting when several or none qualify
courtlistener_get_judge tool
person_idis required; positions are fetched up to a page bound, andtruncatedwithpositionsShownreports when a long record ran past itPositions (judicial, plus non-judicial roles described by
job_titleandorganization_name), education, political affiliations, ABA ratings, andfjc_id; coded fields keep the raw code beside a label (position_type_label,termination_reason_label,degree_label)Dates carry the precision CourtListener recorded in
dob_granularity,dod_granularity,date_start_granularity, anddate_termination_granularity(year,month, orday)
courtlistener_lookup_courts tool
Filter by
jurisdiction(one of 22 CourtListener codes such asF,FD,FB,S,SA; the full table is incourtlistener://reference/courts),status(activedefault,inactive, orany), andhas_opinion_scraper; live records come 20 per page, walked withpagecourts[]carryid(the court ID every other tool filters on),citation_string,jurisdiction, and scraper flags;all_matching_court_idslists every match from a bundled snapshot at no request cost, and is empty when more than 1,000 match, so checkall_matching_court_ids_complete
courtlistener_search_oral_arguments tool
qis required and matches case name and transcript text; filter bycourtandargued_after/argued_before; 20 results per page, continued withnext_cursorResults carry
audio_id(forcourtlistener_get_oral_argument),panel_ids(forcourtlistener_get_judge),duration_seconds,snippet, and two MP3 links:download_urlat the originating court andlocal_path, CourtListener's durable copy
courtlistener_get_oral_argument tool
id(anaudio_idfrom a search) is required;sections: ["transcript"]selects the transcript. Selected responses obey the same byte limits.Returns
panel_ids,duration_seconds,download_url,docket_id,has_transcript, andtranscript; oversized text or metadata usesoutlineand cursor-drivenpageresponses. The argument date is not on this record; take it from the search result or the docket.
courtlistener_search_financial_disclosures tool
Filter by
judge_id(aperson_id) andyear; 20 filings per page, continued withcursor.yearfilters only the fetched page, because CourtListener has no server-side year filter, so keep paging when a page comes back empty withnext_cursorsetEach filing carries
disclosure_id,report_type,has_been_extracted,is_amended,pdf_url, per-categorycounts(investments, gifts, debts, positions, reimbursements, agreements, non-investment and spouse income), and itemizedgifts
courtlistener_get_financial_disclosure tool
disclosure_idis required;categoriesselects frominvestments,debts,positions,reimbursements,non_investment_incomes,spouse_incomes,agreements, andgifts(omit for all)Returns filing metadata,
counts, and the requested line-item rows, with coded value and income columns decoded to dollar ranges (N→$250,001 - $500,000); oversized selections useoutlineand cursor-drivenpageresponses, including when a single row exceeds the budget.
Opinion, audio, disclosure, and selected docket-document retrieval bound each serialized response surface (structuredContent and complete content[]) to 24,000 UTF-8 bytes. Repeat the original identity and selection with cursor: retrieval.next_cursor; docket selections also repeat entries_page. Catalog pages lead automatically to data pages. retrieval.ranges uses JSON Pointer paths and absolute exclusive ranges (rows, code_points, or sections); merge typed rows by absolute index, and concatenate text_chunks by their code-point ranges. Partial rows retain their source identity; omitted text is recoverable through its original field path. Metadata can also be paged. Structured strings remain unescaped; presentation escaping happens after slicing. A changed normalized source returns stale_cursor; restart without cursor. Source-completion cursors remain distinct from these retrieval cursors.
courtlistener://reference/courts resource
Markdown reference: the 22 jurisdiction codes (rendered from the set
courtlistener_lookup_courtsvalidates against), common court IDs, search type codes, the published free-tier rate limits, and the weekly maintenance window (Thursdays 21:00–23:59 PT)Static content, cacheable publicly for 24 hours
skill://courtlistener-guide/SKILL.md resource
Identifier chains and research gates for case law, RECAP filings, judges, disclosures, and oral arguments
Also included in plugin installs, npm, Docker, and the desktop bundle as courtlistener-guide
courtlistener_research_topic prompt
Arguments:
topicrequired;jurisdictionoptional (a court ID such asscotusorca9);depthoptional,overview(default, 3–5 key cases) ordeep(adds citation-network traversal and judge lookup)Returns one user message laying out the research workflow and a findings template: key cases, precedent trajectory, research gaps
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
CourtListener-specific:
CourtListener REST API v4: search, opinions and clusters, dockets and entries, parties and attorneys, people and positions, courts, audio, financial disclosures, and citation lookup
One request queue for the whole process, paced to
COURTLISTENER_RATE_LIMIT_PER_MINUTEandCOURTLISTENER_RATE_LIMIT_PER_HOUR, so a burst waits instead of failing; a 429 pauses the queue for every waiting call, and aRetry-Afteris honored within a 45-second wait budgetRequest cost per call: one for most tools; two for
courtlistener_get_docket; two or more forcourtlistener_get_partiesandcourtlistener_get_judge(one per extra page of a long roster or career); three forcourtlistener_get_opinionandcourtlistener_get_citations(plus one per extra page of opinion variants); and forcourtlistener_lookup_citation, the lookup plus up tomax_court_lookupsdocket requestsInput that can't succeed (an empty
q, a malformed date, a citation over 64,000 characters, an unknown oral argument section) is rejected before a request is spent
Agent-friendly output:
Chaining IDs:
cluster_id,docket_id,person_id,audio_id, anddisclosure_idappear wherever they feed a follow-up call, with field descriptions naming the tool that takes eachTyped rate-limit errors:
reason: "rate_limited"withretryAfterin seconds, whether CourtListener returned the 429 or the queue gave up before sending, in which case the message says no request was spentBounded retrieval: opinion, audio, disclosure, and selected docket-document responses preserve small full records and stream oversized selections through an outline and resumable typed pages without truncating source text
Coverage caveats inline: RECAP
coverage_note,court_resolutionon citation lookups,truncatedon position history, and notices when a page-local filter empties a page that has more pages behind it
Getting started
Connect to the hosted instance, no install:
claude mcp add --transport http courtlistener-mcp-server https://courtlistener.caseyjhand.com/mcpOr run it locally:
claude mcp add courtlistener-mcp-server -e COURTLISTENER_API_TOKEN=your-api-token -- npx -y @cyanheads/courtlistener-mcp-serverFor other clients, add this to the MCP config file:
{
"mcpServers": {
"courtlistener-mcp-server": {
"command": "npx",
"args": ["-y", "@cyanheads/courtlistener-mcp-server"],
"env": {
"COURTLISTENER_API_TOKEN": "your-api-token"
}
}
}
}Generate a token in your CourtListener account settings. Published free-tier limits are 5 requests per minute, 50 per hour, and 125 per day; limits vary by token tier, and Free Law Project membership raises them. For Docker or a source build, see Running the server.
Configuration
Variable | Description | Default |
| Required. API token from your CourtListener account settings. | — |
| API base URL override. |
|
| Requests the server starts per rolling minute. Past it, requests queue; one that can't start within about 45 s fails with the reset time. Raise it to match a higher token tier. |
|
| Requests the server starts per rolling hour. |
|
| Transport: |
|
| HTTP server port. |
|
| HTTP session mode: |
|
| Authentication: |
|
| Log level ( |
|
| Directory for log files (Node.js only). |
|
| Storage backend: |
|
| Enable OpenTelemetry. |
|
| Base endpoint for traces and metrics; appends | — |
| Explicit endpoint for redacted OTLP logs; the base endpoint does not enable log export. | — |
| Log failed-call inputs and results with key-based redaction. |
|
| Size cap for each logged failed-call payload. |
|
See .env.example for the full list of optional overrides.
Running the server
Local development
Requires Bun v1.4.0 or higher (or Node.js v24+).
Clone and install:
git clone https://github.com/cyanheads/courtlistener-mcp-server.git cd courtlistener-mcp-server && bun install cp .env.example .env # set COURTLISTENER_API_TOKENBuild and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:httpRun checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker run --rm -e COURTLISTENER_API_TOKEN=your-token -p 3010:3010 ghcr.io/cyanheads/courtlistener-mcp-server:latestThe image defaults to HTTP transport, stateless session mode, and logs to /var/log/courtlistener-mcp-server. For stdio, use docker run -i --rm -e MCP_TRANSPORT_TYPE=stdio -e COURTLISTENER_API_TOKEN=your-token ghcr.io/cyanheads/courtlistener-mcp-server:latest. To build locally, run docker build -t courtlistener-mcp-server .; OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Resource definitions ( |
| Prompt definitions ( |
| CourtListener API client (request pacing, retry, error classification), code tables, and the bundled court snapshot ( |
| Unit and integration tests mirroring |
| Published research guidance for agents calling the server. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageRegister new tools, resources, and prompts by importing them in
src/index.tsand adding them to thecreateApp({ tools, resources, prompts })arraysWrap CourtListener API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP for CourtListener: US federal and state opinions, dockets, judges, plus eCFR regulations.
CourtListener MCP — Free Law Project's CourtListener API (v4).
Search US federal and state court records through CourtListener and the RECAP archive
PACER Case Locator (PCL) MCP — live US federal court case & party search on the user's OWN PACER…
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables legal research across 3,352 U.S. courts using the CourtListener API, providing access to case search, precedent analysis, judge patterns, citation validation, and federal PACER dockets through natural language queries.14 npm3MIT
- FlicenseNot gradedqualityDmaintenanceA comprehensive Model Context Protocol (MCP) server for accessing CourtListener's legal database. Provides Claude Desktop with powerful legal research capabilities including court opinions, case dockets, judge profiles, and comprehensive legal analysis.1-
- FlicenseNot gradedqualityBmaintenanceEnables LLM-friendly access to the CourtListener legal database and eCFR for searching legal opinions, court cases, judges, documents, and federal regulations.13-
- AlicenseNot gradedqualityDmaintenanceA remotely callable MCP server for US legal research that provides tools to search, retrieve, and analyze US case law from the CourtListener API, enabling agents to build evidence packs from primary sources without generating legal content.MIT