courtmesh-mcp
A CourtMesh MCP server for searching, inspecting, and analyzing Indian court cases through MCP tools.
Keyword/boolean case search across 310M+ records, with court, date/year, case type, judge, page/limit and cursor filters.
Semantic vector search over ~2M embedded cases for natural-language legal-concept questions.
Fetch case details, existing AI analysis, related documents sharing a case number, and procedural timelines.
Search/autocomplete Supreme Court and High Court judge names.
Trigger single-case or consolidated multi-document AI analysis, with credit usage and async/sync behavior.
Get time-limited encrypted PDF links and request/poll live court timelines for cases.
Check upstream API health without authentication.
Click on "Deploy 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., "@courtmesh-mcp Search for Supreme Court cases on right to privacy"
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.
@courtmesh/mcp-server
An MCP (Model Context Protocol) server for the CourtMesh public REST API. It gives any MCP capable AI client, Cursor, or a custom agent, tools to search and analyze Indian court case law, screen a party name for litigation history, and check corpus coverage: 310M plus case records spanning the Supreme Court, High Courts, District Courts and tribunals.
Built with the official @modelcontextprotocol/sdk. MIT licensed.
Quickstart
1. Get an API key
Sign up and generate a key at https://research.courtmesh.ai. Keys look like cm-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxx (a legacy vv- prefix also works).
2. Run it
You do not need to install anything by hand, npx will fetch and run the package. Set COURTMESH_API_KEY in your MCP client config, see the copy pasteable blocks below.
Local checkout:
npm install
npm run build
COURTMESH_API_KEY=cm-your-key-here node dist/index.jsRelated MCP server: canlii-mcp
Environment variables
Variable | Required | Default | Description |
| Recommended | none | Your CourtMesh API key. Tools list fine without it, but any real API call will fail with a 401 style error until it is set. In HTTP mode a per session |
| No |
| Override to point at a different CourtMesh environment. |
| No |
| Set to |
| No |
| Port for the HTTP transport. |
| No |
| Timeout for most tool calls. |
| No |
| Timeout for |
| No |
| Timeout for |
Transports
This server supports two transports, chosen at startup:
stdio (default): the standard transport for local MCP clients such as Cursor and other desktop and command line MCP clients. The client spawns the server process and talks to it over stdin and stdout.
Streamable HTTP: pass
--httpor setMCP_TRANSPORT=httpto run as a long lived HTTP server, mounted at/mcp, suitable for hosting behind a URL such asmcp.courtmesh.ai/mcp. A plainGET /healthroute is also available on the HTTP server itself, separate from thecheck_api_healthtool, which checks the upstream CourtMesh API instead.
Tools
Tool | Endpoint | Credits | One line |
|
| No | Fast keyword and boolean search over the full 310M plus case index. |
|
| Yes | AI vector search over the roughly 2M case subset with embeddings, for natural language questions about legal concepts. |
|
| No | Full case details, without AI analysis. |
|
| Yes | Reads any existing AI analysis for a case, read only. 1 credit per read; the first read of a case by your organization costs the credits generating that analysis used. |
|
| No | Other documents sharing the same case number, plus a procedural timeline. |
|
| No | Autocomplete over Supreme Court and High Court judge names. |
|
| Yes | Triggers AI analysis of one case, asynchronous. |
|
| Yes, more | AI analysis merged across every document sharing a case number, synchronous and slow. |
|
| No | A time limited, encrypted link to the official judgment PDF. |
|
| No, unless | Reads stored order and hearing history by default (1 credit); |
|
| No | Polls the job started by |
|
| Yes | Litigation check for a person or company name: KYC, BGV, due diligence, and litigation/compliance screening. |
|
| No | Corpus coverage and freshness snapshot, no authentication required. |
|
| No | Checks CourtMesh API connectivity, no authentication required. |
|
| No | This key's tier, wallet balance, per period limits and per endpoint call volume for the current month. |
|
| No | The court taxonomy accepted by |
|
| No | Every |
|
| Yes | Screens up to 25 names in one call, same check as |
|
| 1 credit when a record is returned | Finds one case from its 16 character CNR. |
|
| No | Creates a watchlist and optionally starts watching up to 100 CNRs. Daily monitoring is included in your plan, within the watched case cap. |
|
| No | Lists the account's watchlists. |
|
| No | Starts watching 1 to 100 CNRs, with a per case result (watching, pending, invalid, duplicate, cap_exceeded, not_found). |
|
| No | Stops watching one CNR (404 |
|
| No | The cases on a watchlist with their current snapshot (status, stage, next hearing date, order count). A case taken down at a party's request shows as |
|
| 1 credit per non-empty page | The change feed: new orders, hearing date, status, stage and disposal changes. An empty page is free, so polling is cheap. |
25 tools in total. Full input and output field details are in each tool's own description, visible to any connected MCP client through tools/list.
Monitoring a set of cases
Ask the model to watch cases by CNR ("watch DLHC010084212021 and DLHC010084222021 for me"); it creates or reuses a watchlist with create_watchlist and add_cases_to_watchlist. Later, "what changed on my cases since yesterday" is answered by get_case_changes, which returns only new events when you carry its pagination.nextCursor forward. Webhook management is intentionally not exposed as a tool: webhooks send account data to a URL and their signing secret is shown once, so set them up in code with the Node or Python SDK instead.
The monitoring tools do not send an Idempotency-Key: adding a case that is already watched is simply reported as duplicate, so a retry is safe without one.
Idempotency
analyze_case, analyze_consolidated_case, request_case_timeline, screen_party_litigation and screen_party_litigation_batch each send an Idempotency-Key header automatically, derived as a SHA-256 hash of the tool name plus its exact arguments (see computeIdempotencyKey in src/tools.ts). If a model retries one of these calls with identical arguments, whether because of its own retry logic, a dropped connection, or a re-sent turn, the server recognises the replay (same key, same body) and returns the stored response again instead of re-running the job or re-charging credits. Changing even one argument produces a different key and runs as a brand new, separately charged call. This requires no configuration and needs no argument from the calling model.
When a call is served from that cache, the server answers with an Idempotency-Replayed: true header; client.ts turns that into a replayed: true field on the parsed response, and the tool result text for all five of these tools starts with a Replayed: identical request served from the 24 hour idempotency cache, no credits charged. line, so the calling model (and anyone reading a transcript) has a positive, explicit signal instead of having to notice on its own that, for example, screen_party_litigation redacted query.name/query.aliases on that response.
Configuration examples
Any stdio MCP client
Add this to your client's MCP server configuration (the file name and location vary by client; most use an mcpServers object):
{
"mcpServers": {
"courtmesh": {
"command": "npx",
"args": ["-y", "@courtmesh/mcp-server"],
"env": {
"COURTMESH_API_KEY": "cm-your-key-here"
}
}
}
}Cursor
Edit ~/.cursor/mcp.json:
{
"mcpServers": {
"courtmesh": {
"command": "npx",
"args": ["-y", "@courtmesh/mcp-server"],
"env": {
"COURTMESH_API_KEY": "cm-your-key-here"
}
}
}
}Hosted HTTP mode
https://mcp.courtmesh.ai/mcp is live: point any Streamable HTTP capable MCP client at it directly, no local process required. Send your key either as an Authorization: Bearer header (preferred) or as a ?token= query parameter, for clients that can only configure a URL; either form overrides COURTMESH_API_KEY for that session.
Header form:
{
"mcpServers": {
"courtmesh": {
"url": "https://mcp.courtmesh.ai/mcp",
"headers": {
"Authorization": "Bearer cm-your-key-here"
}
}
}
}Query parameter form, for a client that cannot set headers:
{
"mcpServers": {
"courtmesh": {
"url": "https://mcp.courtmesh.ai/mcp?token=cm-your-key-here"
}
}
}Error codes
The API's own error text is always surfaced verbatim where available, along with a plain explanation.
Status | Meaning | What to do |
401 | The API key is missing, malformed, invalid, or deactivated. | Set |
402 | Insufficient credits for the endpoint's price, on any priced call ( | Buy a credit pack or upgrade the plan, then retry. |
403 | Account, plan, or quota gate, distinguished by a machine readable | Check your CourtMesh billing and plan settings, upgrade off the Free tier, pass the flag the error names, or wait for the quota to reset. |
429 | Rate limited, distinguished by | Wait the number of seconds given in |
400 | Validation failed, or a request shape the plan does not allow: | For a plain validation failure, the tool result lists the specific field errors from the API's |
404 | The case, PDF, or timeline request was not found. | Double check the id or requestId. |
408 / 500 / 502 / 503 | Timeout or upstream failure. | Usually transient, retry later. |
When an error body carries a requestId, this server appends it to the reported message so it can be handed to CourtMesh support.
Development
npm install
npm run build # compiles TypeScript with tsc, then chmods dist/index.js executable
npm run dev # tsc --watch
npm start # runs the built server over stdioSource layout:
src/index.ts: entry point, transport selection (stdio vs Streamable HTTP), Express app for HTTP mode.src/client.ts: shared HTTP client, auth headers, and all error mapping.src/tools.ts: tool schemas (zod) and handlers, one per CourtMesh endpoint.src/context.ts: anAsyncLocalStorageused to carry a per request?token=override through to the client in HTTP mode.
See CHANGELOG.md for what changed in each release.
License
MIT, Copyright 2026 Thinkscoop Technologies LLP. See LICENSE.
Available Tools
12 toolsanalyze_caseAnalyze CaseA
Triggers AI analysis of a single case. CONSUMES AI CREDITS. ASYNCHRONOUS: normally returns immediately with status processing while the analysis runs in the background; poll get_case_analysis after roughly 30 to 60 seconds to retrieve the result. If analysis already exists and force is not set, the existing analysis is returned immediately instead with alreadyExists true. Set force true to re-analyze a case that already has analysis, which also consumes credits again. Fails with a clear message if the case has no usable text or PDF content to analyze.
Inputs: id (required), force.
analyze_consolidated_caseAnalyze Consolidated CaseA
Runs AI analysis across ALL documents that share the given case number, producing one merged view of the whole matter. CONSUMES SIGNIFICANTLY MORE AI CREDITS than analyze_case. SYNCHRONOUS: this call blocks until the analysis completes, which can take several minutes, so a long timeout is used. For a High Court case it analyzes the case document plus up to 5 most recent orders. For a Supreme Court case it analyzes up to 20 documents sharing the case number. Set force true to redo analysis that already exists, at the cost of credits again. Fails if the case has no case number or no text content, or if AI credits are exhausted.
Inputs: id (required), force.
check_api_healthCheck API HealthA
Checks whether the CourtMesh API is reachable and healthy. No authentication required and no AI credits consumed. Useful to verify connectivity, and to confirm that connectivity problems are not caused by API key configuration, since this endpoint works even without a key. Returns success, status, version and timestamp; note this endpoint does not use the standard data envelope used by every other tool here.
Inputs: no named parameters.
get_caseGet CaseA
Fetches full details for one case, without AI analysis. No AI credits consumed. Returns id, caseNumber, title, court, caseType, judges, petitioners, respondents, decisionDate, disposalNature, summary, optional metadata.diaryNumber, hasDocuments, documentCount and hasAnalysis. Fields like detailedSummary, headnote, holding and keyFacts are NOT included here, call get_case_analysis for those.
Inputs: id (required).
get_case_analysisGet Case AnalysisA
Reads any existing AI analysis for a case. Read only: does NOT trigger new analysis and does NOT consume AI credits. If analysis has not been generated yet, hasAnalysis will be false and you will get a message field instead of an analysis field; in that case call analyze_case to generate it. When hasAnalysis is true, analysis may include summary, detailedSummary, comprehensiveSummary, headnote, holding, keyFacts, issues, courtsReasoning, citedCases (followed, distinguished, overruled, referred), precedentRelationships, arguments (petitioner, respondent), practiceAreas, subCategories, tags, procedureType, precedentValue, legalPrinciples, doctrinesApplied, statutoryInterpretation and constitutionalProvisions. Fields with no value are omitted from the response.
Inputs: id (required).
get_case_pdf_urlGet Case PDF URLA
Returns a time limited link to the official judgment PDF for a case. No AI credits consumed. CRITICAL: the returned pdfUrl is an ENCRYPTED presigned S3 URL, not a directly fetchable link, it must be decrypted with a case specific key before use, and it expires after the returned expiresIn seconds (normally 3600). Do not attempt to fetch pdfUrl directly, treat it as an opaque token to hand back to the user or to a CourtMesh client that knows how to decrypt it. Returns 404 if the case has no stored document.
Inputs: id (required).
get_case_timelineGet Case TimelineA
Polls the status and result of a job started by request_case_timeline. No AI credits consumed. Returns requestId, status, createdAt, updatedAt plus, when available, startedAt, completedAt, error, result, orders, orderCount and totalOrderCount. Returns 404 if the request is not found, which can mean the requestId is wrong or has expired.
Inputs: requestId (required).
request_case_timelineRequest Case TimelineA
Kicks off a fetch of the live order and hearing history for a case directly from the court's own systems. Asynchronous job, no AI credits consumed. case_id must be the 24 character MongoDB ObjectId string, the id field from search results, a case number will fail. Supreme Court cases return immediately with status completed and orderCount 0, since SC cases have no separate order history in this system. District Court cases are fetched synchronously and come back completed or failed. High Court cases usually return pending and must be polled with get_case_timeline using the returned requestId.
Inputs: case_id (required).
search_indian_court_casesSearch Indian Court CasesA
Keyword and boolean search over the full 310M plus record OpenSearch index of Indian court cases. Fast, exact match, does not consume AI credits. Prefer this over semantic_search_cases for case numbers, party names, citations, judge names and exact phrases. Use semantic_search_cases instead when the request is a natural language question about legal concepts, doctrines or fact patterns rather than exact terms. Note: the caseNumber field is accepted and echoed back but does not actually filter results, put case number text in query instead. Note: sortBy only accepts relevance or date at the validation layer, but the underlying search engine only understands relevance, recent or oldest internally, so date is accepted yet may not reorder results as expected.
Inputs: query (required), page, year, court, +10 more.
search_judgesSearch JudgesA
Autocomplete over the combined Supreme Court and High Court judge name list. No AI credits consumed. Use this to get the exact spelling of a judge name before passing it to search_indian_court_cases as judgeName. Matching is case insensitive substring matching. An empty or omitted q returns the first 50 names in the list. Results are always capped at 50.
Inputs: q.
semantic_search_casesSemantic Search CasesA
AI vector search over the roughly 2M case subset that has embeddings, out of the full 310M plus corpus. CONSUMES AI CREDITS. Prefer this over search_indian_court_cases for natural language questions about legal concepts, fact patterns or doctrines, where exact keywords will not match. Slower, a single call can take a minute or more. Real behaviour note: this endpoint's validation layer also accepts top level court, year, caseType, caseNumber, judgeName, judges, judge, fromDate and toDate fields, but the handler silently ignores all of them, only query, page, limit and filters are actually used, so this tool only exposes those. Put any filtering inside the filters object instead. Another quirk: if the cleaned query text ends up shorter than 3 characters after internal processing, the service falls back to a plain keyword search and marks the response with meta.fallbackMode = "opensearch".
Inputs: query (required), page, limit, filters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 12 tools
Each tool has a distinct purpose: get_case vs get_case_analysis clearly separate raw case data from AI analysis; analyze_case vs analyze_consolidated_case distinguish single vs multi-document analysis; search_indian_court_cases vs semantic_search_cases differentiate keyword vs semantic search; request_case_timeline and get_case_timeline form a clear start/poll pair. No two tools are likely to be confused.
Most tools follow a verb_noun pattern with verbs like get, search, analyze, request, check. There is slight inconsistency: 'find_related_cases' could be 'search_related_cases' or 'get_related_cases', and 'request_case_timeline' uses request while its pair uses get. However, the naming is generally predictable and the intent is clear.
12 tools is well within the ideal 3-15 range. Each tool covers a distinct aspect of legal case research (retrieval, analysis, search, timeline, PDF, health), and none feel redundant or unnecessary. The count matches the apparent scope of the server.
The tool surface provides full coverage for the domain: search cases, get case details, read and generate AI analysis (both single and consolidated), find related cases, retrieve PDFs, and fetch timelines. The addition of search_judges and health check round out the workflow. No major gaps are apparent for the stated purpose of accessing Indian court case data and analysis.
Related MCP Connectors
Connect AI to millions of laws and court cases with the Lawstronaut MCP.
Public Indian legal search MCP for Roop judgments, statutes, and corpus grounding.
One MCP server for all web data. Scrape, search, crawl, and AI research in one install.
Hosted MCP server for live public-data APIs and Skills for AI agents.
Related MCP Servers
- AlicenseBqualityFmaintenanceAn MCP server providing standardized access to Swiss court decisions through the entscheidsuche.ch API, allowing LLMs to search, retrieve, and analyze legal documents from Swiss jurisdictions.35MIT
- AlicenseAqualityCmaintenanceAn MCP server providing AI assistants access to Canadian case law and legislation metadata from CanLII across all jurisdictions, supporting search and citation relationships.735 npm8MIT
- AlicenseAqualityDmaintenanceMCP Server providing AI agents access to over 3 million US court decisions via CourtListener and EU legislation via EUR-Lex, with tools for searching cases, citations, judges, and court information.6MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server providing AI agents access to CourtListener's comprehensive legal database, featuring semantic search, hybrid search, citation verification, and research tools.7MIT