Skip to main content
Glama

ndlaw

A Model Context Protocol (MCP) server for North Dakota Supreme Court opinions, 1889–present (plus a small number of North Dakota Court of Appeals decisions). Coverage is complete since statehood (November 2, 1889); the court issued its first opinions in 1890. Built on SQLite with FTS5 full-text search and served via FastMCP.

The opinions corpus currently contains 20,105 opinions with 127,091 citation links between them, with per-release corrections summarized in the release notes. Where the court's own print contains an apparent typo, the text is preserved verbatim; where that typo is in a citation, the citation graph still resolves it to the case the court meant.

It also serves North Dakota primary law — the Constitution (a point-in-time layer spanning 1889–present), N.D.C.C. statutes, court rules, and the Administrative Code — from separate per-corpus databases. See Primary law below for what each database contains.

Not an official court product. This is an independent, unofficial project. It is not published, endorsed, or maintained by the North Dakota Supreme Court, the North Dakota Court System, or any agency of the State of North Dakota, and nothing here is an official version of any opinion, statute, rule, or regulation. The official sources are the court's own publications (ndcourts.gov) and the Legislative Branch's (ndlegis.gov); verify there before relying on or filing anything.

No claim to official government works. The opinions, statutes, rules, and regulations reproduced here are works of North Dakota's government, reproduced as public documents; this project claims no rights in them. What the project adds — the compilation, corrections, citation graph, and software — is released under CC0 (see NOTICE.md).

This is a working tool, not an authoritative text. See NOTICE.md for sources, redistribution scope, and attribution.

To install it, jump to Quick start below.


MCP tools exposed

Tool

Purpose

lookup_opinion

Retrieve an opinion by any citation (neutral, N.W.2d, N.W.)

get_opinion_text

Read opinion text in paginated chunks

search_opinions

Full-text search with date/author filters

list_opinions_by_date

Browse opinions by date range

get_database_stats

Corpus summary: totals, date range, coverage by decade, most-published authors

justice_info

Voting record for a case, or aggregate stats for a justice

search_by_case_type

Filter by case type (criminal, civil, etc.)

get_citing_opinions

Find opinions that cite a given opinion

verify_citation

Confirm a cite/case name and return its canonical form + Redbook-ordered cites; flags name drift

get_parallel_citations

Return a case's full parallel-cite set (synthetic IDs bracketed separately)

verify_quotation

Confirm a quoted passage is verbatim (typography-tolerant) and return the pinpoint ¶

get_pinpoint

Resolve a paragraph number to its text, or a quote to the ¶ it lives in

check_treatment

Citator: citing opinions with citing-sentence context + a conservative, non-authoritative treatment signal

get_cited_authorities

Outbound authorities a case relies on (cases, statutes, rules, constitution), grouped with source links

case_summary

One-call bench-memo front matter: cites, panel, voting, disposition, ¶ count, syllabus points

get_subsequent_history

Related opinions sharing the docket (rehearings, supplemental, companions)

authoring_justice_on_issue

A justice's authored opinions matching an issue (predictive bench-memo signal)

search_boolean

Westlaw-style Boolean/proximity search (& | % /N /s /p !), translated to FTS5

search_faceted

Filter by date, author, case type, disposition, dissent/concurrence, unanimity (+ optional full text)

find_opinions_construing

Every opinion citing an N.D.C.C. section or court rule, with the official source link

more_like_this

Doctrinally similar opinions (hybrid co-citation + keyword ranking)

detect_overruled_in_draft

Scan a draft's cited cases through the citator; flag possible negative treatment (with citing context)

Primary law (Constitution, court rules, N.D.C.C. statutes, Admin. Code)

Beyond opinions, the server serves North Dakota primary law from separate per-corpus SQLite databases, each ATTACH-ed onto the opinions connection at startup (the server serves whatever corpus DBs are present). All use a shared point-in-time versioned-provision schema, so lookup_authority accepts an as_of_date to return a provision's text as it stood on a given date.

Database

Corpus

Contents (approx.)

opinions.db

ND Supreme Court opinions (+ some Court of Appeals)

20,105 opinions, 127,091 citation links, 1889–present

constitution.db

ND Constitution

~496 provisions / 774 dated versions, point-in-time across the full 1889–present span: a modern article/§ layer (1981–present, with the 1981/1986/1997 article reorganizations and post-1981 amendments reconstructed) + a historical layer in the original 1889 numbering (§§ 1–217 + Schedule + amendment articles, in force 1889–1980), plus the amendment chronology

statutes.db

N.D.C.C. (statutes)

~29,100 Century Code sections

rules.db

ND court rules

~650 rule provisions

admincode.db

ND Administrative Code

~13,800 provisions

ag_opinions.db

ND Attorney General opinions

~6,750 published opinions, 1942–present, cross-linked to the statutes/Constitution/rules/admin/opinions they cite (~35,000 citation links)

Each ships as its own GitHub release asset (<name>.db.zip + .sha256) — see Quick start to install them locally and deploy/SETUP.md for the server-side multi-corpus delivery. Both constitutional layers are as_of_date-queryable: the modern layer by its article/§ citation (e.g. lookup_authority("N.D. Const. art. VIII, § 6", as_of_date="1990-01-01")) and the historical layer by its original 1889 citation (e.g. lookup_authority("N.D. Const. § 82", as_of_date="1945-01-01")). The two numbering schemes are cross-linked through the official 1981 disposition tables (NDCC Replacement Vol. 13): a modern cite at a pre-1981 date returns its original-section predecessor, and an original §-cite at a post-1981 date returns its modern successor — each answer carries provenance (requested_citation, returned_provision, relation, a source note), and lookups that would land past a wholesale article replacement (1982/1986/1997) say so rather than implying content continuity. get_authority_history merges the pre- and post-1981 amendment chronologies into one timeline per provision. The primary-law corpora are newer and less exhaustively validated than the opinions corpus, though the constitution layer has now been verified section-by-section against the official annotated apparatus and every usable printed compilation 1889–1989.

Tool

Purpose

lookup_authority

Text of a constitutional / rule / statute / admin-code provision (with as_of_date for the version in force)

search_authority

Full-text search across the primary-law corpora

get_authority_history

Amendment / version history of a provision

constitutional_amendments

The ND Constitution's amendment chronology

search_ag_opinions

Full-text search across ND Attorney General opinions (1942–present)

lookup_ag_opinion

An AG opinion by number (e.g. 2015-L-12) + the authorities it cites

get_ag_opinions_citing

AG opinions that cite a given statute / constitutional / rule / case authority

get_court_opinions_citing_ag

Court opinions that cite a given AG opinion (the inbound direction)

See Quick start to install the server and Connecting to Claude to wire it into an MCP client.


Related MCP server: America's Law Graph

What's in the database

Counts below are as of 2026-08-21; the corpus total is 20,105 opinions (of which 80 are North Dakota Court of Appeals decisions and the rest North Dakota Supreme Court) — rerun sqlite3 opinions.db "SELECT COUNT(*) FROM opinions" for the live total.

Era

Opinions

Notes

1890–1952

~6,530

includes the court-authored "Syllabus by the Court" that accompanies opinions of this era

1953–1996

~6,300

validation of a residual slice of the earliest N.W.2d years is ongoing

1997–2019

~5,650

neutral-citation era (2019 ND 54)

2020–present

~1,630

The database ships the court's text and the citation graph over it. It does not ship the development record behind that text — the correction history, the working copies collated to produce it, or the pipeline's own bookkeeping. Those are maintained separately and are not needed to read an opinion or to verify a citation. See NOTICE.md for what is and isn't redistributed in text_content, and the release notes for the corrections in each published version.


Quick start

The easy way: let Claude do it

If you're already a Claude user, the simplest install is to ask Claude to do it for you. Paste the prompt below into Claude Code (CLI), Claude Desktop (Mac/Windows), or Claude on the web (claude.ai). Claude will read this repository's README.md and NOTICE.md, detect your platform, walk you through the steps, and — if running in an environment with shell access (Claude Code, or Claude Desktop with appropriate MCP servers) — run them for you. After install it will add the server to your Claude MCP config and verify it works.

Please help me install the ndlaw server from https://github.com/jet52/ndlaw on my computer. Read the repository's README.md and NOTICE.md first so you understand what it is and what it redistributes. Then walk me through (or run for me, if you can) the install steps for my platform, download the latest opinions.db release asset, smoke-test it, and add the server to my Claude MCP config. Stop and ask me before any step that needs a decision.

If you'd rather do it by hand, the manual instructions follow.

1. Prerequisites — all platforms

  • Python 3.12 or newer

  • git

  • ~1 GB of free disk space (for the database)

  • An MCP-capable client (e.g. Claude Desktop, Claude Code) — optional, only needed if you want LLM integration

2. Install the code and database

Pick your platform. The commands install uv, clone the repo, download the latest release of the database, and install the Python dependencies.

Windows (PowerShell)

# Install uv (a fast Python package manager) — skip if already installed
irm https://astral.sh/uv/install.ps1 | iex

git clone https://github.com/jet52/ndlaw.git
cd ndlaw

# Download + extract every database release asset (opinions + primary-law corpora).
# The corpus DBs ship from v0.11.0 on; opinions.db is the only one in older releases.
foreach ($db in "opinions","constitution","statutes","rules","admincode") {
  Invoke-WebRequest `
    -Uri "https://github.com/jet52/ndlaw/releases/latest/download/$db.db.zip" `
    -OutFile "$db.db.zip"
  Expand-Archive "$db.db.zip" -DestinationPath . -Force
  Remove-Item "$db.db.zip"
}

uv sync

macOS

# Install uv — skip if already installed
curl -LsSf https://astral.sh/uv/install.sh | sh

git clone https://github.com/jet52/ndlaw.git
cd ndlaw

# Download + extract every database release asset (opinions + primary-law corpora).
# The corpus DBs ship from v0.11.0 on; opinions.db is the only one in older releases.
for db in opinions constitution statutes rules admincode; do
  curl -LO "https://github.com/jet52/ndlaw/releases/latest/download/$db.db.zip"
  unzip -o "$db.db.zip" && rm "$db.db.zip"
done

uv sync

Linux

# Install uv — skip if already installed
curl -LsSf https://astral.sh/uv/install.sh | sh

git clone https://github.com/jet52/ndlaw.git
cd ndlaw

# Download + extract every database release asset (opinions + primary-law corpora).
# The corpus DBs ship from v0.11.0 on; opinions.db is the only one in older releases.
for db in opinions constitution statutes rules admincode; do
  curl -LO "https://github.com/jet52/ndlaw/releases/latest/download/$db.db.zip"
  unzip -o "$db.db.zip" && rm "$db.db.zip"
done

uv sync

3. Smoke test

Confirm the database is wired correctly:

sqlite3 opinions.db "SELECT COUNT(*) FROM opinions"          # exact count
# Primary-law corpora (if you downloaded them):
sqlite3 constitution.db "SELECT COUNT(*) FROM provisions"    # ~496
sqlite3 statutes.db     "SELECT COUNT(*) FROM provisions"    # ~29,100

Updating to a newer database release

When a new database release is published, replace the local copy:

# macOS / Linux — refresh every database (or list just the ones you use)
for db in opinions constitution statutes rules admincode; do
  rm -f "$db.db"
  curl -LO "https://github.com/jet52/ndlaw/releases/latest/download/$db.db.zip"
  unzip -o "$db.db.zip" && rm "$db.db.zip"
done
# Windows PowerShell
foreach ($db in "opinions","constitution","statutes","rules","admincode") {
  Remove-Item "$db.db" -ErrorAction SilentlyContinue
  Invoke-WebRequest `
    -Uri "https://github.com/jet52/ndlaw/releases/latest/download/$db.db.zip" `
    -OutFile "$db.db.zip"
  Expand-Archive "$db.db.zip" -DestinationPath . -Force
  Remove-Item "$db.db.zip"
}

Then git pull to pick up any code changes since the release was cut.

4. Run

MCP server (stdio mode, for Claude Desktop / Claude Code):

uv run ndlaw-mcp

Connecting to Claude

The server can run under any MCP client. The two most common are Claude Code (CLI, all platforms) and Claude Desktop (Mac and Windows only — no Linux build is shipped today).

Throughout the snippets below, replace /absolute/path/to/ndlaw with the full path to your cloned repo. On Windows you can use forward slashes in JSON strings (C:/Users/you/ndlaw) — they work fine and avoid double-backslash escaping.

Claude Code (Windows, macOS, Linux)

One-liner from any directory:

claude mcp add ndlaw -- uv --directory /absolute/path/to/ndlaw run ndlaw-mcp

This stores the server in your user-level Claude Code config and makes it available in every project. Restart any active Claude Code session and the ndlaw server's tools will be available.

Alternative: a project-scoped .mcp.json in any project where you want ndlaw available. Create the file with:

{
  "mcpServers": {
    "ndlaw": {
      "type": "stdio",
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/ndlaw",
               "run", "ndlaw-mcp"]
    }
  }
}

Claude Desktop (macOS)

Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "ndlaw": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/ndlaw",
               "run", "ndlaw-mcp"]
    }
  }
}

Then quit and restart Claude Desktop (Cmd-Q, not just close the window).

Claude Desktop (Windows)

Edit %APPDATA%\Claude\claude_desktop_config.json. Same JSON shape, but specify the absolute paths to both uv and your repo. If uv is on your PATH (it is by default after the install script), "command": "uv" works; otherwise use the full path, e.g. "C:/Users/you/.local/bin/uv.exe".

{
  "mcpServers": {
    "ndlaw": {
      "command": "uv",
      "args": ["--directory", "C:/Users/you/ndlaw",
               "run", "ndlaw-mcp"]
    }
  }
}

Then quit and restart Claude Desktop from the system tray.

Linux

Claude Desktop is not available on Linux. Use Claude Code (above).

Verifying the connection

Once connected, try a prompt like:

Use ndlaw to look up State v. Boger, 2021 ND 152.

The tool call should return the case metadata and (with include_text=true) the opinion text. For the full set of tools, see the MCP tools exposed table near the top.


Remote / team deployment

By default the server speaks stdio — each user runs their own copy and their MCP client launches it as a subprocess (the configs above). To serve a whole team from one host instead, the same server can run over Streamable HTTP. The opinion data is public (CC0), so the goal of auth here is access control, not secrecy; the recommended posture is work-network / VPN-only with a bearer token, with TLS and the token check handled by a reverse proxy in front of the app.

The only thing the app itself needs is three environment variables:

Variable

Purpose

Default

NDLAW_TRANSPORT

http (Streamable HTTP) or sse; anything else = stdio

stdio

NDLAW_HOST

bind address — keep 127.0.0.1 so only the local proxy can reach it

127.0.0.1

NDLAW_PORT

bind port

8000

NDLAW_DB

path to opinions.db on the server

bundled / app-data

NDLAW_CONST_DB

path to constitution.db (ND Constitution corpus)

bundled / app-data

NDLAW_NDCC_DB

path to statutes.db (N.D.C.C. corpus)

bundled / app-data

NDLAW_RULE_DB

path to rules.db (court-rules corpus)

bundled / app-data

NDLAW_ADMIN_DB

path to admincode.db (Admin. Code corpus)

bundled / app-data

NDLAW_AG_DB

path to ag_opinions.db (Attorney General opinions)

bundled / app-data

The MCP endpoint is /mcp (no trailing slash — /mcp/ issues a 307 redirect, which some clients mishandle on POST).

The tools are read-only (search / lookup / citation analysis); the data-editing CLIs are not exposed over MCP.

Run it as a service (systemd)

# /etc/systemd/system/ndlaw-mcp.service
[Unit]
Description=ndlaw-mcp (Streamable HTTP)
After=network.target

[Service]
User=ndcourts
WorkingDirectory=/srv/ndcourts/ndlaw-mcp
Environment=NDLAW_TRANSPORT=http
Environment=NDLAW_HOST=127.0.0.1
Environment=NDLAW_PORT=8000
Environment=NDLAW_DB=/srv/ndcourts/opinions.db
ExecStart=/srv/ndcourts/ndlaw-mcp/.venv/bin/ndlaw-mcp
Restart=on-failure

[Install]
WantedBy=multi-user.target

Terminate TLS and enforce the token (Caddy)

mcp.court.example {
    # only requests carrying the shared token reach the app
    @authorized header Authorization "Bearer REPLACE_WITH_A_LONG_RANDOM_TOKEN"
    handle @authorized {
        reverse_proxy 127.0.0.1:8000
    }
    respond "Unauthorized" 401
}

For revocable, per-person access, give each user a distinct token and add a matching @authorized line per token. Restrict the host's firewall so the proxy port is reachable only from the VPN subnet.

What each team member runs

claude mcp add --transport http ndlaw https://mcp.court.example/mcp \
  --header "Authorization: Bearer REPLACE_WITH_A_LONG_RANDOM_TOKEN"

(Claude Desktop: add an equivalent "type": "http" server with a headers block in claude_desktop_config.json.) Users connect to the VPN first, then the client reaches the server.

Updating the deployed database

The weekly pipeline regenerates opinions.db. Because it is served read-only, deploying an update is just: copy the new file to the server, then systemctl restart ndlaw-mcp.

Public VPS test (open internet)

The model above is VPN-only with a bearer token. To instead expose the server on the public internet for a quick test — with TLS + HTTP Basic Auth + rate limiting + fail2ban — use the ready-to-run Ubuntu templates in deploy/:

  • deploy/SETUP.md — step-by-step Ubuntu 22.04/24.04 walkthrough (system user, uv install, database download, systemd, Caddy with the rate-limit plugin, ufw, SSH hardening, fail2ban, client config).

  • deploy/Caddyfile — auto-HTTPS, per-IP rate_limit, basic_auth, and flush_interval -1 so MCP's SSE streaming isn't buffered.

  • deploy/ndlaw-mcp.service — hardened systemd unit bound to localhost.

  • deploy/fail2ban/ — filter + jail that ban IPs on repeated 401s.

The data is public (CC0), so this auth is access control and abuse prevention, not secrecy.


Sources, redistribution scope, and license

Code: dedicated to the public domain under CC0 1.0 Universal. Use it however you want.

Data: the opinions database redistributes only the court's own published work (opinions and court-authored syllabi) plus factual record content (parties, dates, attorneys, dispositions, citations). Judicial opinions of state courts are edicts of government and are not protected by copyright; what is published here is the North Dakota courts' own text. See NOTICE.md for the redistribution scope in full.


Reporting errors

This repository ships a validated, read-only corpus and the minimal server that serves it; the data pipeline and its correction history are maintained separately. If you find a text or metadata discrepancy against an official source, please open an issue with the citation and the source you checked against.

A
license - permissive license
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

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

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables users to search, retrieve, and validate over 11,000 Philippine statutes and nearly 100,000 provisions through AI-powered legal research tools. It supports full-text search across Republic Acts, the Constitution, and various codes while providing cross-referencing and international law alignment capabilities.
    1
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides access to 529,000+ US statute sections across all 50 states and federal codes for comprehensive legal research. Supports semantic search, citation graph traversal, jurisdictional comparisons, and regulatory risk analysis through natural language queries.
    32
    2
    MIT
  • A
    license
    A
    quality
    F
    maintenance
    Provides access to 1,709 Icelandic statutes and 19,026 provisions with full-text search, citation validation, and EU/EEA law integration, enabling legal research and compliance checks through natural language queries.
    11
    93
    1
    Apache 2.0

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

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/jet52/ndlaw'

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