MCP

Integrate Midpage's legal database with AI assistants using the Model Context Protocol.

Note: MCP supports court opinion research. Federal docket report and filing analysis tools, plus statute and regulation tools (searchLaws, analyzeLaw), are available in preview in v3.

Versioning

These docs describe the current MCP contract, v3.

Midpage uses major versions for tool contract changes that integrations may need to account for, such as output schema changes or newly introduced tools. If your integration depends on fixed tool schemas or output fields, use a pinned version endpoint.

Previous version docs and migration notes:

Base URL

https://app.midpage.ai/mcp/v3

Use this pinned URL for the v3 contract documented here.

If you want your integration to automatically receive the latest tool implementations, use the unversioned URL instead:

https://app.midpage.ai/mcp

Authentication

Midpage supports two authentication models for MCP integrations.

Option Best for How it works
API key Server-side integrations, internal tools, and quick prototypes Your integration sends one shared API key with each request.
OAuth End-user apps, partner integrations, and multi-tenant products Each user signs in with their own Midpage account and your client sends that user's access token.

1. API Key

Use API key auth for non-interactive access, server-side jobs, or any integration that should run under one shared credential.

Generate an API key in the Developer Portal. If you need help, contact support@midpage.ai. Then send it in your MCP request headers as:

Authorization: Bearer <api_key>

2. OAuth

Use OAuth when your client should connect each user to their own Midpage account. Each user will need a Midpage account before they can sign in and authorize your client.

For most customers, the easiest setup is:

  1. Point your client at https://app.midpage.ai/mcp/v3
  2. Let your MCP or OAuth library follow Midpage's discovery metadata and register a client automatically if it supports dynamic client registration
  3. Let the user sign in and approve access when prompted

Most MCP clients should not need pre-provisioned OAuth app credentials. Midpage's Clerk auth server supports dynamic client registration, so compatible clients can create their own credentials automatically. If your client cannot do that and needs a pre-provisioned OAuth app, contact Midpage.

Need the manual OAuth settings?

If your client supports discovery, start there. In most cases, pointing it at https://app.midpage.ai/mcp/v3 is enough. Midpage publishes protected-resource metadata on app.midpage.ai, and that metadata points clients to the Clerk authorization server. The settings below are only for cases where you need to configure the OAuth flow yourself.

Discovery

  • MCP protected-resource metadata: https://app.midpage.ai/.well-known/oauth-protected-resource/mcp
  • Clerk OAuth metadata: https://clerk.midpage.ai/.well-known/oauth-authorization-server
  • Clerk OIDC discovery: https://clerk.midpage.ai/.well-known/openid-configuration

Some older MCP clients expect OAuth authorization-server metadata on the same origin as the MCP server. Midpage currently publishes protected-resource metadata on app.midpage.ai and authorization-server metadata on the Clerk domain above, so older clients may need manual configuration using those Clerk URLs.

The current metadata advertises:

  • authorization server: https://clerk.midpage.ai
  • dynamic client registration endpoint: https://clerk.midpage.ai/oauth/register
  • PKCE challenge method: S256
  • resource scopes: profile, email

Which OAuth flow to use

  • Public clients such as desktop apps, mobile apps, browser apps, and local CLIs should use Authorization Code + PKCE (S256). Do not embed a client_secret in those clients. If you need this mode, Midpage can provision your Clerk OAuth app as a public client.
  • Confidential server-side apps can use Authorization Code and exchange the code on their backend with either client_secret_basic or client_secret_post.
  • If you need refresh tokens for long-lived sessions, request offline_access.

Minimal flow

  1. Fetch the protected-resource metadata document and read authorization_servers.
  2. Fetch the Clerk authorization-server or OIDC metadata document and use the published endpoints.
  3. Start an authorization request with response_type=code, client_id, redirect_uri, state, and the resource value from the protected-resource metadata document.
  4. Request profile email for MCP access. Add openid if your client expects an ID token. Add offline_access if you need a refresh token.
  5. Public clients must also send code_challenge and code_challenge_method=S256.
  6. Exchange the authorization code for tokens at the Clerk token endpoint, again including the same resource value.
  7. Call the MCP server with Authorization: Bearer <access_token>.

Example authorize request for a public client

GET https://clerk.midpage.ai/oauth/authorize?
  response_type=code&
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://your-app.com/oauth/callback&
  resource=https%3A%2F%2Fapp.midpage.ai&
  scope=profile%20email%20openid%20offline_access&
  state=RANDOM_VALUE&
  code_challenge=BASE64URL_SHA256(code_verifier)&
  code_challenge_method=S256

Example token exchange for a public client

curl -X POST "https://clerk.midpage.ai/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://your-app.com/oauth/callback" \
  -d "resource=https://app.midpage.ai" \
  -d "code_verifier=YOUR_CODE_VERIFIER"

Example token exchange for a confidential client

curl -X POST "https://clerk.midpage.ai/oauth/token" \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://your-app.com/oauth/callback" \
  -d "resource=https://app.midpage.ai"

Calling the MCP server

Authorization: Bearer <access_token>

Testing in Hosted MCP Clients

If you just want to try Midpage in Claude, Codex, Perplexity, Cursor, or another hosted MCP client, add https://app.midpage.ai/mcp/v3 and sign in with your Midpage account when prompted.

You can create a free trial account at app.midpage.ai. For production integrations, use API key auth or OAuth as described above.

Available Tools

The latest MCP contract exposes:

  • search
  • findInOpinion
  • analyzeOpinion
  • analyzeDocketReport (preview)
  • analyzeDocketFiling (preview)
  • searchLaws (preview)
  • analyzeLaw (preview)

The docket tools and the laws tools are in preview: available now, but their contracts may change as we refine the workflows.

Search US case law across federal and state courts. Returns metadata, highlights, and citator treatment data.

Parameters:

Parameter Type Required Description
queries array Yes Array of search queries (1-4) run in parallel
queries[].query string Yes Search query
queries[].startDate string No Start date (inclusive, YYYY-MM-DD)
queries[].endDate string No End date (inclusive, YYYY-MM-DD)
queries[].jurisdictionType string No "federal", "state", or "state_and_federal"
queries[].circuits string[] No Federal circuits: "1"-"11", "dc", "federal_circuit", "supreme_court"
queries[].states string[] No State names (e.g., ["California", "New York"])
queries[].publishStatus string No "published", "unpublished", "unknown", "in_chambers", "separate", "errata", or "relating_to"
queries[].courts string[] No Bluebook-style court abbreviations to narrow the search, such as ["S.D.N.Y.", "9th Cir."]

If you filter on publishStatus, consider also running a parallel query with "unknown" because some jurisdictions have missing or uncertain publication metadata.

Example:

{
  "queries": [
    {
      "query": "breach of fiduciary duty elements",
      "jurisdictionType": "state_and_federal",
      "states": ["California"],
      "publishStatus": "published"
    },
    {
      "query": "breach of fiduciary duty elements",
      "jurisdictionType": "state_and_federal",
      "states": ["California"],
      "publishStatus": "unknown"
    }
  ]
}

findInOpinion

Find quotable passages within a single opinion using keyword search.

Parameters:

Parameter Type Required Description
opinionId string No* Midpage document ID (e.g., "7228818")
reporterCitation string No* Bluebook citation (e.g., "556 U.S. 662")
docket object No* Court and docket number pair
docket.courtAbbreviation string Yes Court abbreviation (e.g., "S.D.N.Y.", "9th Cir.")
docket.docketNumber string Yes Docket number (e.g., "12-cv-20100")
query string Yes Key terms to match

* Provide one of opinionId, reporterCitation, or docket

Example:

{
  "opinionId": "7228818",
  "query": "minimum contacts purposeful availment"
}

analyzeOpinion

Reads the full document, then answers your question and returns the answer alongside text excerpts.

Accepts either opinionId, reporterCitation, or docket as input.

Parameters:

Parameter Type Required Description
opinionId string No* Midpage document ID
reporterCitation string No* Bluebook citation (e.g., "556 U.S. 662")
docket object No* Court and docket number pair
docket.courtAbbreviation string Yes Court abbreviation (e.g., "S.D.N.Y.", "9th Cir.")
docket.docketNumber string Yes Docket number (e.g., "12-cv-20100")
question string Yes The legal question you want answered

* Provide one of opinionId, reporterCitation, or docket

Example:

{
  "reporterCitation": "556 U.S. 662",
  "question": "What standard does this case establish for pleading requirements?"
}

Output fields:

Field Type Description
opinionId string Midpage opinion ID
question string The question that was analyzed
citation string Bluebook citation for the opinion
url string General Midpage document URL
supportedPropositions array Propositions the opinion actually supports
supportedPropositions[].proposition string Cite-ready proposition supported by the quote
supportedPropositions[].quote string Verbatim supporting text from the opinion
supportedPropositions[].scope string Limits, conditions, or context for the proposition
supportedPropositions[].centrality string core_holding, supporting_analysis, secondary_matter, or background
supportedPropositions[].opinionSection string Optional source label for non-majority opinions, such as a concurrence or dissent
supportedPropositions[].deeplinkURL string Midpage URL linked to the supporting line range
doesNotAddress string[] Topics from the question the opinion does not address
summary string Short summary of what the case is about
disposition string Short procedural outcome phrase
jurisdiction string Court and jurisdiction
treatment object Citator treatment summary

Example output:

{
  "opinionId": "7228818",
  "question": "What does this case hold?",
  "citation": "Example v. Case, 1 F.4th 1 (9th Cir. 2024)",
  "url": "https://app.midpage.ai/document/7228818",
  "supportedPropositions": [
    {
      "proposition": "The court adopted the rule.",
      "quote": "We adopt the rule.",
      "scope": "Applies in the stated procedural posture.",
      "centrality": "core_holding",
      "opinionSection": "Smith, Concurring",
      "deeplinkURL": "https://app.midpage.ai/document/7228818?lines=10-12"
    }
  ],
  "doesNotAddress": [],
  "summary": "The court adopted a rule.",
  "disposition": "affirming judgment",
  "jurisdiction": "9th Circuit",
  "treatment": {
    "status": "positive",
    "citedBy": 10
  }
}

analyzeDocketReport (preview)

Analyze a federal docket report and answer a docket-level question. Use this for case snapshots, recent activity, procedural posture, service, complaint history, motion history, deadlines, and identifying filings that should be reviewed next.

This tool answers from the docket sheet. If the text of a specific filing is needed, use analyzeDocketFiling with the returned case.caseId and a relevantEntries[].filingId.

Parameters:

Parameter Type Required Description
court string Yes Federal court. Prefer Bluebook-style abbreviations such as "N.D. Cal.", "S.D.N.Y.", "D. Del.", "Bankr. D. Del.", "9th Cir.", or "Fed. Cir.". Full federal court names are also accepted.
docketNumber string No Federal case docket number. Prefer full district or bankruptcy numbers with office or division prefix when known, such as "4:24-cv-04722"; appellate numbers look like "24-1234".
caseName string No Optional case caption/name, such as "Musk v. Altman". Include it when available, especially if the docket number is incomplete.
question string Yes The docket-level question to answer.

Example:

{
  "court": "N.D. Cal.",
  "docketNumber": "4:24-cv-04722",
  "caseName": "Musk v. Altman",
  "question": "Give me a case snapshot and identify the operative complaint."
}

Output fields:

Field Type Description
status string "ok" or a specific resolution/analysis error
case object Resolved case metadata
case.caseId string Case ID to use with analyzeDocketFiling
case.caseName string Resolved case caption, when available
case.court string Resolved court
case.docketNumber string Resolved docket number
docketReport object Docket report file metadata
docketReport.url string Downloadable Midpage file URL for the docket report
docketReport.suggestedFileName string Suggested filename if saving the docket report
answer string Direct answer based only on the docket sheet
relevantEntries array Docket entries or attachments supporting the answer or worth reviewing next
relevantEntries[].filingId string Filing ID to pass to analyzeDocketFiling, when available
relevantEntries[].entryNumber string Docket entry number
relevantEntries[].attachmentNumber string Attachment number, when the relevant filing is an attachment
relevantEntries[].description string Docket entry description, when available
relevantEntries[].relevance string Why the entry matters
doesNotAddress string[] Parts of the question the docket report does not answer
warnings string[] Optional warnings about report coverage or parsing

analyzeDocketFiling (preview)

Analyze one docket filing selected from analyzeDocketReport and answer a focused question using passages from that filing. Use this when the user needs to understand what a specific filing says, not just what the docket entry says.

Parameters:

Parameter Type Required Description
caseId string Yes case.caseId returned by analyzeDocketReport
filingId string Yes relevantEntries[].filingId returned by analyzeDocketReport
question string Yes The question to answer about this specific filing

Example:

{
  "caseId": "00000000-0000-0000-0000-000000000000",
  "filingId": "11111111-1111-1111-1111-111111111111",
  "question": "What claims are asserted in this complaint?"
}

Output fields:

Field Type Description
status string "ok" or a specific resolution/analysis error
filing object Resolved filing metadata
filing.caseId string Case ID
filing.filingId string Filing ID
filing.entryNumber string Docket entry number
filing.dateFiled string Filing date, when available
filing.description string Docket entry description for the filing
filing.url string Downloadable Midpage file URL for the filing
filing.suggestedFileName string Suggested filename if saving the filing
answer string Direct answer based only on the filing text
supportingPassages array Passages from the filing supporting the answer
supportingPassages[].passage string Supporting passage text
supportingPassages[].relevance string Why the passage matters
doesNotAddress string[] Parts of the question the filing text does not answer

When citing filing content in a user-facing answer, hyperlink the citation to filing.url. Include the ECF number in the citation when available, for example: [Pl.'s Mot. for Summ. J. 5, ECF No. 30 (Mar. 3, 2020)](<filing.url>).


searchLaws (preview)

Full-text search over statutes, regulations, constitutions, and agency guidance — US federal plus all 50 states and DC. Use it to FIND the governing provision, then call analyzeLaw with the result's id before citing it. Results are current law by default (see the Laws API guide for the currency derivation). Inputs are strict: unknown keys are rejected rather than silently ignored.

Parameters:

Parameter Type Required Description
query string Yes Legal concepts / key terms (BM25 keyword search)
states string[] No State names or USPS abbreviations ("California", "TX"); federal law is "Federal". Validated server-side — unrecognized values error with did-you-mean suggestions
collectionTypes string[] No statute, regulation, constitution, guidance, executive_order, notice
collections string[] No Specific codes, by id (e.g. "cfr", "wa-rcw") or human-readable name (e.g. "Code of Federal Regulations", "Texas Administrative Code") — resolved server-side; unresolvable values error with did-you-mean suggestions
pathPrefix string No Subtree filter within one code — a dot-separated ltree path from a previous result (e.g. "cfr.t21" = all of 21 CFR, including descendants); pair with collections. Malformed prefixes error rather than matching nothing
currentOnly boolean No Default true — only the law in force today
page, pageSize number No Pagination (max 50 per page; results beyond the first 10,000 cannot be paginated)

Returns:

Field Type Description
results array Matching provisions: id, citation, title, number, jurisdiction and path fields, dates, isCurrent / isHistorical, snippets (matched fragments), and url (the Midpage page for that exact version)
total number Estimate for the whole query; a page can hold fewer than pageSize results
stateCounts object Estimated per-state hit counts for the WHOLE query — for state surveys, run one unfiltered query and read this, then verify per state with a filtered search
error string Set instead of results when a filter could not be resolved or the pagination window was exceeded — the message says how to fix the call

Never cite from snippets — they are relevance context. Call analyzeLaw with the result id and quote from its verified passages.

Example:

{
  "query": "telehealth prescribing controlled substances",
  "collectionTypes": ["regulation"],
  "states": ["California", "Texas"]
}

analyzeLaw (preview)

Analyze a statute, regulation, constitutional provision, or agency guidance document against a specific legal question, returning verified verbatim passages — the document text is analyzed internally and raw text is never returned. Resolves to the CURRENT version by default (see the Laws API guide for how currency is derived); container nodes return their children for navigation; versioned provisions return the full version chain with dates.

Parameters (provide exactly one of the four lookup keys):

Parameter Type Required Description
citation string No* Canonical citation (e.g., "42 U.S.C. § 1983", "Cal. Code Regs. tit. 22, § 51451"). Matching ignores punctuation, spacing, and §/sec./section style ("42 USC 1983" works), but not abbreviation differences — use the jurisdiction's canonical wording
registerCitation string No* Federal Register / state register citation (e.g., "89 FR 12345")
path string No* Full ltree path from a previous result (pair with collection)
id string No* Document UUID from a previous result
question string Yes The legal question to answer about the document
collection string No Disambiguates path/citation/registerCitation lookups — a collection id (e.g., "cfr", "uscode") or human-readable name (e.g., "Code of Federal Regulations"); unresolvable values error with did-you-mean suggestions
includeHistorical boolean No Allow superseded / future-effective versions in citation/path/registerCitation lookups (default: current law only); id always returns that exact version

* Provide exactly one of citation, registerCitation, path, or id

Returns:

Field Type Description
citation, title, number string Identification of the provision
registerCitation string FR / state-register cite, for regulations that carry one
collectionId, collectionName string The code the provision belongs to (e.g. cfr / "Code of Federal Regulations")
effectiveDate, publicationDate string Source-stated dates (null when the source states none)
analysis object summary, passages (point + verified verbatim quote + deeplinkUrl, a Midpage link that opens the provision at the quoted passage), doesNotAddress — aspects of the question the document does not cover; check it before citing. Absent for containers without their own text
children array For containers: up to 250 child provisions (id, number, citation, title, sortOrder) — navigation only, analyze a child by its id; childrenTotal is the true count
versions array Version chain with dates and isHistorical / isCurrent / isRequested flags (empty without history)
parentId string Container node id — look it up to zoom out
isCurrent, isHistorical boolean Whether this text is the law in force today / whether it has been superseded
state, collectionType string Jurisdiction ("Federal" or state name) and statute/regulation/constitution/guidance/executive_order/notice
url, sourceUrl string Midpage link for this exact version (non-current versions carry ?version=) and official source link
ambiguousMatches array When the reference matched several documents — candidate summaries; retry with one match's id
error string The reference could not be resolved or the provision could not be analyzed — the message says how to proceed (some provisions are review-only via url)

Example:

{
  "citation": "21 C.F.R. § 820.30",
  "question": "What design control requirements apply to medical device manufacturers?"
}

Changelog

See the MCP changelog for version history and migration notes.