Legal Research from Inside Cursor and Claude Code: The MCP Way

Short answer: To run legal research MCP in Cursor or Claude Code, add a legal MCP server to your config and point your assistant at it. For US statutes and regulations, add a statutes-and-regs MCP (for example, Vaquill AI's): run claude mcp add vaquill --transport http https://mcp.vaquill.ai (Claude Code), or add the same url to ~/.cursor/mcp.json for Cursor. Then ask the assistant something like "pull 17 CFR 240.10b-5 and the related sections," and it queries the live statutory corpus instead of guessing.

TL;DR

  • Claude Code, Cursor, and Claude Desktop all speak the Model Context Protocol, so the same legal MCP servers work in all three with small config differences.
  • Add a statutes-and-regs MCP for the US Code, CFR, and state statutes, the one slice the open ecosystem still does not normalize cleanly. Vaquill AI ships a hosted one at https://mcp.vaquill.ai.
  • The hidden failure mode is rate limits: most off-the-shelf wrappers package a 429 as a success-shaped response, and that silence is what makes a model fabricate a citation. Fix it with typed errors plus retry with full-jitter backoff.
  • Treat the setup as a credential-handling system: never commit raw keys, use ${env:VAR} interpolation, and run a server-side proxy for shared firm deployments.
Quick check

What does the Vaquill AI statutes MCP at mcp.vaquill.ai cover?

Part of our MCP and developer guide series.

For related MCP / API / developer coverage, see How to Use Claude for US Legal Research (with MCP).

The Brief That Almost Went Out With a Hallucinated Case

A friend (call her D) was finishing a motion to dismiss the day before filing. She had three authorities cited in a single paragraph.

Her editor was Cursor, the assistant was Claude, and the legal MCP stack was wired in. The prompt was the kind of thing you write at 11:47 PM: "verify these three citations resolve to real opinions and pull the holdings."

The model came back with a clean answer. Three citations, three holdings, three URLs.

The third hit looked the most authoritative: a Ninth Circuit excessive-force opinion from 2023, parties she half-recognized, a one-line holding that read like it had been lifted from the syllabus. She would have shipped it.

The non-obvious operational failure: the third tool call had returned a 429 from the upstream, but the MCP wrapper packaged that 429 as a successful tool response with an error string in the payload.

Cursor's tool panel rendered three green checkmarks. The server log was telling a very different story.

2026-05-22T03:47:11Z INFO  citation_lookup citation="568 U.S. 519" status=200 ms=412
2026-05-22T03:47:12Z INFO  citation_lookup citation="710 F.3d 1003" status=200 ms=389
2026-05-22T03:47:13Z WARN  citation_lookup citation="84 F.4th 1234" status=429 retry_after=8
2026-05-22T03:47:13Z WARN  upstream rate_limited remaining=0 reset_in=8s
2026-05-22T03:47:13Z ERROR tool returned error to client: rate_limited

The third citation hit a 429 from the upstream case-law API. The wrapper bubbled it back to the client as a plain error string. Cursor showed the tool as "completed" because the call itself returned, just with an error payload.

The model, with no result to lean on and a green checkmark on its UI, did what models do when they are stranded mid-paragraph: it produced a holding and a court that sounded right. The case existed (the citation pointed at a real opinion, since 84 F.4th is a real volume). The holding did not.

Caught with eight minutes to spare. The fix was not a better model. The fix had two parts.

The wrapper needed to retry the 429 with backoff. And when retries were exhausted, it needed to surface a typed RateLimited error as a structured tool error, not as a string.

Frontier models, including Claude, respect structured tool errors: they back off, ask the user, or refuse the citation. They guess when they get an opaque blob that looks like a normal response. Most off-the-shelf MCP wrappers ship with the opaque-blob behavior. If you are putting one into a lawyer's editor, you fix it before anyone files anything.

That story is the whole reason this post exists.

The Statutes-and-Regs MCP for US Practice

No single MCP server covers the full primary-law surface a US lawyer touches in a day, and the hardest slice to wire up yourself is statutes and regulations.

A statutes-and-regs MCP covers the US Code, the CFR, and the statutes of the states. This is the piece that costs money because the open ecosystem still does not have a clean, normalized multi-state statutes corpus.

eCFR covers federal regs; state statutes are a mess of legislature websites with their own schemas and update cadences. A maintained wrapper here saves the integration tax. Vaquill AI ships a hosted one at https://mcp.vaquill.ai covering the US Code, CFR, and 49 state codes (around 2.6M sections total). Note that this server is statutes-and-regs only; it does not return case law.

For case-law lookups in your editor you can add a separate server. Vaquill AI's own case-law research (millions of US court opinions) lives in the Vaquill AI workbench, not in the statutes MCP.

Claude Desktop Config

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent path on Windows / Linux:

{
  "mcpServers": {
    "vaquill": {
      "url": "https://mcp.vaquill.ai",
      "headers": {
        "Authorization": "Bearer YOUR_VAQUILL_KEY"
      }
    },
    "us-statutes-alt": {
      "command": "uvx",
      "args": ["us-statutes-mcp"],
      "env": {
        "STATUTES_API_KEY": "YOUR_KEY"
      }
    }
  }
}

Restart Claude Desktop. The statutes servers read keys from the config. Then ask "what MCP tools are available?". You should see the statute-search and section-lookup tools listed. If you do not, the logs are at ~/Library/Logs/Claude/mcp-server-*.log. Read them.

The usual suspects are a trailing comma in the JSON or a stale token. Less obvious is that Claude Desktop will silently disable a server that takes more than ~10 seconds to start up, so if your stdio server warms up slowly (a fat Python import tree on first run), wrap it in a script that backgrounds the warmup.

Claude Code Config

Claude Code (the CLI / IDE harness) takes MCPs via the claude mcp add command. One line per server:

claude mcp add vaquill --transport http \
  --header "Authorization: Bearer $VAQUILL_KEY" \
  https://mcp.vaquill.ai

claude mcp add us-statutes-alt --transport stdio \
  --env STATUTES_API_KEY=$STATUTES_API_KEY \
  -- uvx us-statutes-mcp

Run claude mcp list to confirm both show up. The statutes servers use the keys you passed. One trap: --header flags do not expand shell variables the way --env does in some shells, so if a key shows up literally as $VAQUILL_KEY server-side, use double quotes and confirm with claude mcp list --verbose.

Keep your tokens in ~/.zshenv or a .envrc (with direnv), not in your shell history.

Cursor Config

Cursor reads MCP servers from ~/.cursor/mcp.json (global) or .cursor/mcp.json in the repo root (per-project). For a per-project setup that travels with the matter:

{
  "mcpServers": {
    "vaquill": {
      "type": "streamableHttp",
      "url": "https://mcp.vaquill.ai",
      "headers": {
        "Authorization": "Bearer ${env:VAQUILL_KEY}"
      }
    },
    "us-statutes-alt": {
      "type": "stdio",
      "command": "uvx",
      "args": ["us-statutes-mcp"],
      "env": {
        "STATUTES_API_KEY": "${env:STATUTES_API_KEY}"
      }
    }
  }
}

The ${env:VAR} syntax matters. Hard-coding a key into .cursor/mcp.json and then git push-ing the repo is the most common way legal-tech tokens end up in public on GitHub. We will come back to this in the security section.

Settings → MCP → enable the servers, then reload the window.

Transport gotcha worth knowing

Cursor calls the HTTP transport streamableHttp. Claude Code calls the same thing http. Claude Desktop infers it from the URL shape.

If you copy a JSON block between editors and leave "type": "streamableHttp" in a Claude Code config, the CLI silently refuses to register the server and there is no popup explaining why. Check claude mcp list after every edit.

The same trap shows up with stdio servers when uvx is not on the editor's resolved PATH (Cursor on macOS launched from the dock has a stripped PATH; Cursor launched from a terminal does not). If stdio servers work from one and not the other, that is usually the reason. Put the absolute path to uvx in the config, or launch the editor from a shell.

The 429 Pattern, Done Right

The near-miss above had one root cause: the MCP wrapper did not handle 429 gracefully, and it did not tell the model what had failed. Both halves matter.

Here is a server-side log slice from a properly behaved wrapper after the fix:

2026-06-04T18:22:09Z INFO  tool=search_opinions q="qualified immunity" status=200 ms=487
2026-06-04T18:22:10Z INFO  tool=citation_lookup citation="84 F.4th 1234" status=429 retry_after=8
2026-06-04T18:22:10Z INFO  backoff sleep=623ms attempt=1
2026-06-04T18:22:11Z INFO  tool=citation_lookup citation="84 F.4th 1234" status=429 retry_after=6
2026-06-04T18:22:11Z INFO  backoff sleep=1287ms attempt=2
2026-06-04T18:22:13Z INFO  tool=citation_lookup citation="84 F.4th 1234" status=200 ms=512
2026-06-04T18:22:13Z INFO  tool=citation_lookup result_count=1 cluster_id=9482137

Two retries, then success. Total latency: about four seconds. The model got a real opinion record back and did not need to guess.

The retry loop, in TypeScript, looks like this:

type FetchOpts = { headers?: Record<string, string> };

async function fetchWithBackoff(
  url: string,
  opts: FetchOpts = {},
  maxRetries = 3,
): Promise<Response> {
  const baseMs = 500;
  const capMs = 8000;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = await fetch(url, opts);

    if (res.status !== 429 && res.status !== 503) {
      return res;
    }
    if (attempt === maxRetries) {
      throw new RateLimitedError(`upstream ${res.status} after ${attempt} retries`);
    }

    // Honor Retry-After if the server sent one, else exponential backoff with full jitter.
    const retryAfter = Number(res.headers.get("retry-after"));
    const exp = Math.min(capMs, baseMs * 2 ** attempt);
    const jittered = Math.floor(Math.random() * exp);
    const sleepMs = Number.isFinite(retryAfter) && retryAfter > 0
      ? retryAfter * 1000
      : jittered;

    await new Promise((r) => setTimeout(r, sleepMs));
  }
  throw new RateLimitedError("unreachable");
}

class RateLimitedError extends Error {
  constructor(msg: string) { super(msg); this.name = "RateLimitedError"; }
}

Two details. First, full jitter (random between zero and the exponential ceiling) is what AWS recommends and what prevents a multi-client server from thundering-herding the upstream after a brief outage. We tried equal-jitter and "exponential without jitter" first; both produced visible retry spikes in the audit log when more than three lawyers were on the wrapper at once. Full jitter flattened the curve.

Second, on exhaustion you throw a typed error so the MCP client sees a structured tool error, not a string blob. Frontier models respect typed errors and refuse to fabricate; they guess on opaque strings.

The same discipline applies whatever the upstream is: a structured error on exhaustion is what lets you tell a client where every cite came from, instead of letting the model paper over a gap.

For multi-user deployments, do not retry from a single shared queue. Per-token queues prevent one heavy user from starving everyone else and stop another tenant's burst from poisoning your backoff state.

Three Workflows That Actually Save Time

Three prompts that pay for the setup the first week:

1. Targeted circuit-court precedent.

"Find Ninth Circuit cases on qualified immunity from 2023 involving excessive force. Pull the top five, one-paragraph summaries with full citations, flag any later treatment."

Case-law research like this runs in the Vaquill AI workbench, which searches millions of US court opinions, pulls full text on strong hits, and synthesizes. Without it, this is ten minutes of Boolean searching and tab-swapping.

2. Cite-check a paragraph. Paste a paragraph and ask:

"Extract every citation, resolve each, tell me which are correct, misformatted, or do not exist."

Vaquill AI's case-law research surface extracts each citation and resolves it against the opinion corpus, producing a structured pass/fail list.

The hallucinated citation that would have cost you a Rule 11 hearing shows up as resolved: false.

3. Pull a specific regulation. When you need 17 CFR 240.10b-5:

"Pull 17 CFR 240.10b-5 and any cases from the last three years that meaningfully construe scienter under it."

The statutes MCP pulls the reg; the workbench's case-law search finds the construing cases. Click through to verify. This is the workflow that retires a Westlaw tab.

None of the three require you to leave the editor. None require you to trust the model's memory for anything load-bearing.

Security Checklist

A legal MCP setup is a credential-handling system before it is anything else. If a token leaks, your firm's name is attached to whatever the abuser does next. Run this list before you deploy to anyone but yourself.

  • Never put a raw API key in a config file you commit to git. Use ${env:VAR} interpolation (Cursor) or environment variables sourced from a .envrc (Claude Code, Claude Desktop). Add .cursor/mcp.json to .gitignore if it has secrets in it at all. Better: keep the file template-only and load keys from the environment.
  • For shared firm deployments, run a server-side proxy. Do not give every associate a copy of the same upstream API key. Run the MCP server behind a small gateway that holds the upstream key, authenticates internal callers, and rate-limits per user. This also gives you the per-token queue from the previous section for free.
  • Rotate keys quarterly. Put it on the calendar. The statutes MCP key needs rotation; for OAuth-based servers, revoke the authorization in your account instead of rotating a pasted token. Rotation is the cheapest defense you have against a stale leak.
  • Audit-log every tool call, server-side. Tool name, caller identity, query parameters (redact PII), upstream status, latency. Six months of retention is enough to investigate an incident; cheaper than a SIEM and proves to the partner-in-charge that you can answer "what did this assistant actually do."
  • Pin MCP server versions; never run latest. When you write uvx some-mcp you are pulling whatever was published five minutes ago. Pin to a version (uvx some-mcp==1.4.2) and bump deliberately. A compromised dependency in an MCP server has direct access to the keys you handed it.
  • Disable destructive tools or gate them behind explicit confirmation. Some MCPs include delete_* or update_* tools that have no place in a research workflow. Read the tool list. Disable the ones you do not need.
  • Treat the LLM as untrusted on tool arguments. Validate inputs server-side. If a tool takes a citation string, validate the format before you ping the upstream. Cheaper than a 429 cascade caused by a malformed batch.

Most of those items get skipped because the setup starts as "just for me" and then five other lawyers in the firm ask for the same configs a month later. Plan for that on day one.

What This Actually Saves

Pilot across one solo and two small firms, April and May 2026:

  • Cite-check of a motion paragraph (four to six citations): 12 minutes by hand on Westlaw, about 90 seconds with the MCP retrieval plus synthesis. The 90 seconds includes clicking through to verify the two highest-stakes citations against the source.
  • Hallucination catch rate: 1 of 14 draft paragraphs contained a citation that did not resolve. The MCP retrieval caught every one before the lawyer did. Zero reached a filed document.
  • Regulation pull (CFR section plus three years of construing cases): 8 to 10 minutes manually, around 2 minutes with the stack.
  • Editor vs. research-portal time: flipped. Pre-MCP, roughly 35 percent of research time stayed inside the drafting editor. Post-MCP, about 80 percent. The remaining 20 percent was treatise work and Shepard's / KeyCite, neither of which the open stack covers.

Three firms, two months, mid-sized civil matters. Not a randomized trial.

Take the absolute numbers with a grain of salt; the directional shift is what mattered to the partners we shared the data with.

A Note on Trajectory

A year ago, "AI for legal research" meant a chatbot in a web tab. MCP changes the geometry: the assistant lives inside the editor where lawyers already draft, and retrieval, synthesis, and citation verification all happen against the same buffer. If you want to push this further into a full drafting-and-research loop, see how to build your own legal AI stack on Claude plus MCP.

The incumbents will get there eventually; the question is whether they ship before the editor-native pattern is already the default. You can have most of the workflow now with three free-or-cheap servers, a config file, a real retry policy, and the security checklist taped to the wall.

FAQ

Open ~/.cursor/mcp.json (global) or .cursor/mcp.json in the repo root (per-project) and add the server under mcpServers. For a statutes MCP like Vaquill AI's, add a "url": "https://mcp.vaquill.ai" entry and use headers with ${env:VAR} interpolation for the key. Save, go to Settings, then MCP, enable the server, and reload the window.

Use the claude mcp add command, one line per server. For US statutes and regs: claude mcp add vaquill --transport http --header "Authorization: Bearer $VAQUILL_KEY" https://mcp.vaquill.ai. Run claude mcp list to confirm it registered, then ask the assistant a statutory question and it will call the tool. Claude Code calls the HTTP transport http, while Cursor calls it streamableHttp, so do not copy a type value between the two.

What does the Vaquill AI statutes MCP cover?

It is a hosted remote MCP server at https://mcp.vaquill.ai covering the US Code, the CFR, and 49 state codes (around 2.6M sections total). It is statutes-and-legislation only: it does not return case law, dockets, or AI answers. Case-law research lives in the Vaquill AI workbench instead.

It depends on the server. Key-based servers such as a statutes MCP read a key you store as an environment variable and reference with ${env:VAR} rather than hard-coding it into a committed config. OAuth-based servers authorize in the browser instead.

Why does my AI assistant make up case citations?

The common cause is silent tool failure. When a legal MCP wrapper hits a rate limit (HTTP 429) and packages that failure as a success-shaped response, the model has no real result and fills the gap with a holding that sounds right. Fix it by returning typed errors and retrying with full-jitter backoff so the model gets either a real record or a structured error it can refuse on.

Yes. Edit ~/Library/Application Support/Claude/claude_desktop_config.json on macOS (or the equivalent on Windows or Linux) and add the same servers under mcpServers. Claude Desktop infers the HTTP transport from the URL shape, so you do not set a type.

Treat it as a credential-handling system. Never commit raw keys, keep config files template-only, run a server-side proxy that holds the upstream keys and rate-limits per user, audit-log every tool call, and pin server versions instead of running latest. Plan for the shared case on day one, because a "just for me" setup usually gets copied across the team within a month.


Vaquill AI workflows view showing chained research and drafting steps running as one automated sequence

For the statutes-and-regs slot, Vaquill AI ships a hosted statutes-and-legislation MCP (US Code, CFR, and 49 state codes). It is statutes-and-legislation only: it does not return case law. Vaquill AI's own case-law research lives in the workbench, not the MCP.

If you would rather get citation-verified statutory research inside a workbench than wire it up yourself, the same corpus backs Vaquill AI's legal research surface, or email contact@vaquill.ai.

Legal AI that reads your documents and knows the law.
Ask a legal question, review a contract, or search thousands of your files. Every answer shows where it came from. 7-day free trial, no card.
17 min read

New legal AI guides, weekly.

Priyansh Khodiyar

Priyansh Khodiyar

Co-Founder & CTO

Priyansh leads engineering and AI at Vaquill, from the matter workbench to drafting, document comparison, document matrix, and citation-verified research.