@cyanheads/courtlistener-mcp-server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@cyanheads/courtlistener-mcp-serverget opinion details for 410 U.S. 113"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://courtlistener.caseyjhand.com/mcp
Tools
14 tools spanning the full CourtListener dataset — opinion search and retrieval, citation network traversal, federal docket lookup, party and attorney lookup, judge biography, judicial financial disclosure search and detail, court discovery, and oral argument search and detail:
Tool | Description |
| Full-text search across 9M+ written court opinions with field-level filtering, date ranges, status, and sort |
| Fetch full text and metadata for an opinion cluster — returns all opinion variants (majority, concurrence, dissent) |
| Retrieve the citation network for an opinion: opinions cited by it ( |
| Resolve legal citations (e.g., "410 U.S. 113") to cluster IDs and case metadata — one entry per citation found in the input |
| Search RECAP federal court dockets by party name, attorney, court, and date |
| Fetch docket metadata and entry list for a single federal case |
| Fetch all parties and attorneys of record for a RECAP federal docket by docket ID |
| Search judge records by name, appointing president, court, and political affiliation |
| Fetch full biographical profile, appointment history, and education for a single judge |
| List courts filtered by jurisdiction type, active/inactive status, and scraper coverage |
| Search appellate oral argument audio recordings by case name, court, and date argued |
| Fetch full detail for a single oral argument — panel, duration, MP3 link, and speech-to-text transcript |
| Search federal judicial financial disclosure filings by judge and year — category counts, itemized gifts, and source PDF |
| Fetch one disclosure's parsed line items — investments, debts, positions, income, gifts — with coded values decoded to dollar ranges; selectable by category |
courtlistener_search_opinions
Search the 9M+ opinion corpus. Returns opinion cluster summaries with matched text excerpts.
Free-text queries with field syntax:
caseName:,court_id:,judge:,docketNumber:,cites:(id), booleanAND / OR / NOTFilter by court ID, date range, publication status (Published / Unpublished / In-chambers, etc.)
Sort by relevance score, filing date (asc/desc), or citation count
Cursor-based pagination; up to 20 results per call
Results include
cluster_id(forcourtlistener_get_opinion) anddocket_id(forcourtlistener_get_docket) for chainingEach cluster carries its
opinions[]variants — per-variant opinion ID, type, author, outbound cites, and a CourtListener-hostedlocal_pathcopy of the source documentsnippetis the matched excerpt from the first variant that carries one; CourtListener does not mark which variant the search matched
courtlistener_get_opinion
Fetch full text and metadata for an opinion cluster.
A cluster groups all opinions filed in a case: majority, concurrence, dissent, per curiam
Returns
html_textandplain_textfor each opinion variant; surfacesdownload_urlwhen local text is absentEach variant carries
type_label— the same valuecourtlistener_search_opinionsreports (lead-opinion,concurrence-opinion,dissent) — beside the storedtypecode, whose numeric prefix is a sort keyIncludes
cites[](outbound citation IDs),cite_count, syllabus, posture, and docket linkThree upstream requests — the cluster, its opinion variants, and the linked docket for court and docket number — kept within the tight free-tier rate limit
courtlistener_get_citations
Retrieve the citation network for an opinion cluster in either direction.
cited_by(default): opinions that cite this one — measures precedential influence and downstream adoptionciting: opinions this one cites — reveals the authority chain the court relied onOptional court and date filters; up to 20 results per call
Pagination differs by direction:
cited_byfollows CourtListener's own cursor with the filters applied, so its total and its pages describe the same set;citingwalks the cited-opinion list and filters each page as it goes, so a filtered page can come back empty with matches still ahead — the response distinguishes that from an exhausted networkResults include
snippet, the matched excerpt from the related opinion — a relevance preview for the cluster, not necessarily the text surrounding the citationRate-limit note: three upstream requests per call in either direction; the free tier supports 1–2 hops on a single case, and deep multi-hop traversal exhausts the daily budget quickly
courtlistener_lookup_citation
Resolve legal citations to opinion cluster IDs.
Accepts standard reporter formats: "410 U.S. 113", "347 U.S. 483", "93 S. Ct. 705"
Returns
matches, one entry per citation CourtListener extracted from the input — pass a passage and every citation in it resolves, each with its ownstatus(200 one case, 300 several candidates, 400 unrecognized reporter, 404 no match) and decodedstatus_labelEach match carries the cases it resolved to:
cluster_id,case_name,court/court_id,court_resolution,docket_id,date_filed, all known citation strings,cite_count,precedential_status, andjudgesAn unresolved or ambiguous citation comes back inside
matches, not as an error — only text carrying no parseable citation at all failscourtis absent from the citation-lookup payload (the court lives on the linked docket), so it is resolved fromdocket_id— one extra request per distinct docket, bounded bymax_court_lookups(default 4, up to 20; 0 skips court resolution).court_resolution(resolved/no_docket/lookup_failed/over_budget) says why a court is or isn't populated — onlyover_budgetis worth retrying with a larger budgetOne upstream POST to
/citation-lookup/plus those court lookups, issued sequentially and stopped early on the first rate-limited response. The endpoint requires authentication and has no unauthenticated path
courtlistener_search_dockets
Search RECAP federal court dockets.
Query matched against case name, docket number, party names, and attorney names
party_namefilter applies in addition to (AND with) theqquery — more precise than embedding party names in the queryReturns the docket's
parties,attorneys, andfirms, plus nature of suit, jurisdiction type, and the referred magistrate judgeReturns up to 3 sample document entries per docket — a search excerpt, not the full filing list — each with
is_availablestatus, page count, and a fully-qualified RECAP storage URL when a copy is storedcoverage_notein every response — RECAP is crowd-sourced from PACER; completeness varies by court
courtlistener_get_docket
Fetch full docket metadata and entry list for a single federal case.
Returns all available docket entries with document availability, page count, and RECAP file path
entries_page_sizecontrols how many entries are returned (1–50); large cases have hundredsDocuments with
is_available: falserequire a PACER account or CourtListener RECAP filing — document retrieval is not exposed
courtlistener_get_parties
Fetch all parties and attorneys of record for a RECAP federal docket.
Returns each party's name, docket-scoped role (Plaintiff, Defendant, Petitioner, Respondent, etc.), and the attorneys of record on this docket with contact information
Attorney roles are decoded to labels (
Lead attorney,Terminated, …) alongside the raw code, with the date a relationship endedAttorney names and contact details are resolved from the docket's attorney roster — 2 upstream requests per invocation, plus one for each extra roster page on a docket with a large attorney list
Paginate large party lists by passing a response's
next_cursorback ascursor— this endpoint is cursor-paginated, so there is no page number to increment;page_size(max 10) is a request only, and CourtListener paginates at a fixed size that can return more parties than asked forObtain docket IDs from
courtlistener_search_docketsorcourtlistener_get_docket
courtlistener_search_judges
Search judge and person records across the federal and state bench.
Filter by appointing president's last name, court ID, or political affiliation (
d/r/i/l/g/u)Returns
person_idfor chaining tocourtlistener_get_judge, plus acurrent_positionsummary — court, position type, appointer, selection method, and start date — selected as the position with no termination date, or the latest-starting one when several or none qualifyPolitical affiliations and ABA ratings come back as expanded labels ("Democratic", "Well Qualified"), not the codes the
political_affiliationfilter takesCourt IDs from
courtlistener_lookup_courtscan be passed directly
courtlistener_get_judge
Fetch a judge's full biographical profile.
Position history: all courts served, position type, appointer, nomination date, confirmation date, termination reason — plus non-judicial roles, which carry no court and describe themselves in
job_titleandorganization_name./positions/is cursor-walked under a page bound; atruncatednotice andpositionsShown/truncatedfields report when a long career ran past itPosition type, termination reason, and degree level come back decoded (
position_type_label,termination_reason_label,degree_label) alongside the raw codes CourtListener's own filters takeBirth, death, and position dates carry the precision CourtListener recorded —
dob_granularityand the per-positiondate_start_granularityreadyear,month, orday, and a year-only record renders as the year rather than the storedYYYY-01-01placeholderEducation records with school, degree, and year
Political affiliations with date ranges; ABA ratings; Federal Judicial Center ID for cross-referencing
courtlistener_lookup_courts
List courts with optional jurisdiction and scraper filters.
Jurisdiction codes mirror CourtListener's own
Court.JURISDICTIONS— federal appellate (F), federal district (FD), federal bankruptcy (FB), state supreme (S), state appellate (SA), plus the tribal, territory, and military benches. The full table is in thecourtlistener://reference/courtsresourcestatusselects which bench to return:active(the default) only the courts CourtListener still scrapes,inactiveonly the historical and defunct ones,anyboth. Upstream filters these as disjoint sets, soanyis the only value that reaches the whole listhas_opinion_scraperfilter useful for planning opinion searches — courts without scrapers have sparse coverageReturns
id(thecourt_idstring for use in all search and filter parameters), citation string (e.g., "9th Cir."), and jurisdiction codePage-number paginated at a fixed 20 rows per page —
/courts/ignores any requested page size, so there is no way to pull a larger page. Enumerating a whole bench costs one call per 20 courts against a rate-limited free tier, and the inactive bench is several times larger than the active one:status: 'any'makes the full set reachable, not cheap. Filter byjurisdictionto answer a question in one call; pass a response'snext_cursorback aspagewhen you genuinely need to walkall_matching_court_idsreturns the complete filtered id set from a bundled snapshot of every CourtListener court, at no request cost — covers the default bench and every jurisdiction filter. Empty (not a truncated prefix) when more than 1,000 courts match; checkall_matching_court_ids_completebefore reading emptiness as "no courts match". The livecourtspage stays authoritative for full records
courtlistener_search_oral_arguments
Search appellate oral argument audio recordings — the largest public collection of oral argument audio.
Query matched against case name and transcribed argument text (where available)
Filters by court, argued-after, and argued-before date
Returns two MP3 links per recording —
download_urlat the originating court, andlocal_path, CourtListener's durable hosted copy — plusduration_seconds,panel_ids(chaining tocourtlistener_get_judge), and transcriptsnippet
courtlistener_get_oral_argument
Fetch the full detail record for a single oral argument by audio ID.
Returns the speech-to-text
transcriptwhen transcription has completed, pluspanel_ids,duration_seconds, MP3download_url, and the linkeddocket_idAudio IDs come from
courtlistener_search_oral_argumentsresultsThe argument date is not on this record — take it from the search result or the linked docket
courtlistener_search_financial_disclosures
Search federal judicial financial disclosure filings for ethics and recusal research.
Filter by
judge_id(aperson_idfromcourtlistener_search_judges) and/or filingyearThe
yearfilter is applied to the fetched page only — CourtListener has no server-side year filter, so filings for that year on later pages are not included; page through withcursor(the response returnsnext_cursoreven when the current page has no year match)Returns per-filing category counts (investments, gifts, debts, positions, reimbursements, income), itemized gifts, and a link to the source PDF
Line-item investments — often hundreds per filing, with coded values — are summarized as counts; the linked PDF carries the full itemization
courtlistener_get_financial_disclosure
Fetch one disclosure's parsed line items in full — the itemized companion to the search tool.
Keyed by
disclosure_id(from acourtlistener_search_financial_disclosuresresult); one upstream call returns every category inlineReturns filing metadata, per-category counts, and the requested line-item rows — investments, debts, positions, reimbursements, non-investment and spouse income, agreements, and gifts
Coded income/value columns are decoded to readable dollar ranges (e.g.
N→$250,001 - $500,000)Pass
categories: [...]to select specific categories; omit for all. When the full itemization is too large to inline, the response returns an outline of categories by size — re-call withcategories: [...]to pull specific ones in full
Related MCP server: CourtListener MCP Server
Features
Built on @cyanheads/mcp-ts-core:
Declarative tool definitions — single file per tool, framework handles registration and validation
Unified error handling across all tools
Pluggable auth (
none,jwt,oauth)Swappable storage backends:
in-memory,filesystem,Supabase,Cloudflare KV/R2/D1Structured logging with optional OpenTelemetry tracing
STDIO and Streamable HTTP transports
CourtListener-specific:
Complete CourtListener REST API v4 integration — opinions, dockets, judges, courts, oral arguments, citation network
Rate-limit-aware client: 429 responses classified by window (minute / hour / day) with actionable error messages; retry with Retry-After respect
Pagination matched to each endpoint's own paginator — cursor-based on the
/search/-backed tools and on parties/attorneys, page-number on the courts and docket-entry lists — with continuation surfaced on every responseRECAP coverage note surfaced on every docket response — sets expectations on partial PACER mirror completeness
Tight upstream-call budget — most tools make 1–2 calls; opinion detail and citation traversal make three (resolving the linked docket, or the source cluster's opinion variants), plus one per extra page of variants on a case that filed many. Citation lookup is the ceiling at five, resolving up to four distinct dockets for their courts
Agent-friendly output:
Chaining IDs on every response —
cluster_id,docket_id, andperson_idfields are present wherever they enable a logical follow-up call, with field-level descriptions naming which tool to pass them toDiscriminated rate-limit errors — minute / hour / day throttle identified in structured error so agents can reason about retry timing, not just "try again later"
Coverage caveats inline — RECAP
coverage_noteand oral argument transcriptsnippetavailability explicitly signaled so agents can communicate limitations to users rather than silently omitting them
Getting started
Public Hosted Instance
A public instance is available at https://courtlistener.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"courtlistener-mcp-server": {
"type": "streamable-http",
"url": "https://courtlistener.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Add the following to your MCP client configuration file. See CourtListener account settings to generate a free API token.
{
"mcpServers": {
"courtlistener-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/courtlistener-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"COURTLISTENER_API_TOKEN": "your-api-token"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"courtlistener-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/courtlistener-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"COURTLISTENER_API_TOKEN": "your-api-token"
}
}
}
}Or with Docker:
{
"mcpServers": {
"courtlistener-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "COURTLISTENER_API_TOKEN=your-api-token",
"ghcr.io/cyanheads/courtlistener-mcp-server:latest"
]
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 COURTLISTENER_API_TOKEN=... bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.3.2 or higher (or Node.js v24+).
A CourtListener API token — free account at courtlistener.com. CourtListener publishes free-tier limits of 5 req/min, 50 req/hr, 125 req/day; actual limits vary by token tier. Free Law Project membership unlocks higher limits.
Installation
Clone the repository:
git clone https://github.com/cyanheads/courtlistener-mcp-server.gitNavigate into the directory:
cd courtlistener-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env and set COURTLISTENER_API_TOKENConfiguration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
Variable | Description | Default |
| Required. API token from your CourtListener account settings. CourtListener's published free-tier limits are 5 req/min, 50/hr, 125/day; actual limits vary by token tier. | — |
| API base URL override. |
|
| Transport: |
|
| HTTP server port. |
|
| HTTP endpoint path. |
|
| Public origin for TLS-terminating reverse-proxy deployments. | — |
| Auth mode: |
|
| Log level ( |
|
| Opt-in Bun-only forced-GC pressure loop (ms). Try |
|
| Directory for log files (Node.js only). |
|
| Storage backend: |
|
| Enable OpenTelemetry instrumentation. |
|
See .env.example for the full list of optional overrides.
Running the server
Local development
Build 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 build -t courtlistener-mcp-server .
docker run --rm -e COURTLISTENER_API_TOKEN=your-token -p 3010:3010 courtlistener-mcp-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/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 ( |
| CourtListener REST API client — auth, retry, rate-limit error classification. |
| Unit and integration tests mirroring |
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 by importing them in
src/index.tsand adding to thecreateApp({ tools: [...] })arrayWrap CourtListener API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceEnables 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.162MIT
- Flicense-qualityDmaintenanceA 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
- Flicense-qualityFmaintenanceEnables LLM-friendly access to the CourtListener legal database and eCFR for searching legal opinions, court cases, judges, documents, and federal regulations.12
- Alicense-qualityCmaintenanceA 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
Related MCP Connectors
MCP for CourtListener: US federal and state opinions, dockets, judges, plus eCFR regulations.
CourtListener MCP — Free Law Project's CourtListener API (free, no auth required for basic access)
Federal court records and PACER case data. 4 MCP tools for legal research.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/cyanheads/courtlistener-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server