Skip to main content
Glama
README.md
# @courtmesh/mcp-server

An MCP (Model Context Protocol) server for the CourtMesh public REST API. It gives any MCP capable AI client, Claude Desktop, Claude Code, Cursor, or a custom agent, tools to search and analyze Indian court case law: 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](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:

```bash
npm install
npm run build
COURTMESH_API_KEY=cm-your-key-here node dist/index.js
```

## Environment variables

| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| `COURTMESH_API_KEY` | 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 `?token=` query parameter overrides this. |
| `COURTMESH_API_BASE_URL` | No | `https://research.courtmesh.ai/api/v1/prod` | Override to point at a different CourtMesh environment. |
| `MCP_TRANSPORT` | No | `stdio` | Set to `http` to run the Streamable HTTP transport instead of stdio. Equivalent to passing `--http`. |
| `PORT` | No | `3000` | Port for the HTTP transport. |

## Transports

This server supports two transports, chosen at startup:

- **stdio** (default): the standard transport for local MCP clients such as Claude Desktop, Claude Code and Cursor. The client spawns the server process and talks to it over stdin and stdout.
- **Streamable HTTP**: pass `--http` or set `MCP_TRANSPORT=http` to run as a long lived HTTP server, mounted at `/mcp`, suitable for hosting behind a URL such as `mcp.courtmesh.ai/mcp`. A plain `GET /health` route is also available on the HTTP server itself, separate from the `check_api_health` tool, which checks the upstream CourtMesh API instead.

## Tools

| Tool | Endpoint | Credits | One line |
| --- | --- | --- | --- |
| `search_indian_court_cases` | `POST /search/cases` | No | Fast keyword and boolean search over the full 310M plus case index. |
| `semantic_search_cases` | `POST /search/cases/semantic` | Yes | AI vector search over the roughly 2M case subset with embeddings, for natural language questions about legal concepts. |
| `get_case` | `GET /cases/{id}` | No | Full case details, without AI analysis. |
| `get_case_analysis` | `GET /cases/{id}/analysis` | No | Reads any existing AI analysis for a case, read only. |
| `find_related_cases` | `GET /cases/{id}/related` | No | Other documents sharing the same case number, plus a procedural timeline. |
| `search_judges` | `GET /judges/search` | No | Autocomplete over Supreme Court and High Court judge names. |
| `analyze_case` | `POST /cases/{id}/analyze` | Yes | Triggers AI analysis of one case, asynchronous. |
| `analyze_consolidated_case` | `POST /cases/{id}/analyze-consolidated` | Yes, more | AI analysis merged across every document sharing a case number, synchronous and slow. |
| `get_case_pdf_url` | `GET /cases/{id}/pdf` | No | A time limited, encrypted link to the official judgment PDF. |
| `request_case_timeline` | `POST /request-timeline` | No | Kicks off a live fetch of order and hearing history from the court's own systems. |
| `get_case_timeline` | `GET /get-timeline/{requestId}` | No | Polls the job started by `request_case_timeline`. |
| `check_api_health` | `GET /health` | No | Checks CourtMesh API connectivity, no authentication required. |

Full input and output field details are in each tool's own description, visible to any connected MCP client through `tools/list`.

## Configuration examples

### Claude Desktop

Edit `claude_desktop_config.json` (Settings, Developer, Edit Config) and add:

```json
{
  "mcpServers": {
    "courtmesh": {
      "command": "npx",
      "args": ["-y", "@courtmesh/mcp-server"],
      "env": {
        "COURTMESH_API_KEY": "cm-your-key-here"
      }
    }
  }
}
```

### Claude Code

CLI one liner:

```bash
claude mcp add courtmesh --env COURTMESH_API_KEY=cm-your-key-here -- npx -y @courtmesh/mcp-server
```

Or add to `.mcp.json` in your project:

```json
{
  "mcpServers": {
    "courtmesh": {
      "command": "npx",
      "args": ["-y", "@courtmesh/mcp-server"],
      "env": {
        "COURTMESH_API_KEY": "cm-your-key-here"
      }
    }
  }
}
```

### Cursor

Edit `~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "courtmesh": {
      "command": "npx",
      "args": ["-y", "@courtmesh/mcp-server"],
      "env": {
        "COURTMESH_API_KEY": "cm-your-key-here"
      }
    }
  }
}
```

### Hosted HTTP mode

Once this server is deployed behind a public URL, point any Streamable HTTP capable MCP client at it directly, no local process required. Pass your key as a query parameter, it overrides `COURTMESH_API_KEY` for that session:

```json
{
  "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 `COURTMESH_API_KEY` to a valid key, or fix the `?token=` value in HTTP mode. Get a key at https://research.courtmesh.ai. |
| 403 | Account, plan, or quota gate: organization deactivated, account suspended, billing inactive, account not found, AI credits exhausted, or the daily API call quota reached (the response includes `callsToday` and `maxAllowed` when this is a quota gate). | Check your CourtMesh billing and plan settings, or wait for the quota to reset. |
| 429 | Rate limited. | Wait the number of seconds given in `retryAfter` before retrying, the message also states when the limit resets. |
| 400 | Validation failed. | The tool result lists the specific field errors from the API's `details` array, fix the input and retry. |
| 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. |

There is one API quirk this server handles for you: `POST /search/cases/semantic` sends its HTTP 200 status before it finishes work, so a failure inside that endpoint can still arrive as HTTP 200 with a body of `{"success": false, "error": "..."}`. Every tool call checks for `success: false` in the response body in addition to the HTTP status, and reports it as a tool error either way.

## Development

```bash
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 stdio
```

Source 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`: an `AsyncLocalStorage` used to carry a per request `?token=` override through to the client in HTTP mode.

## License

MIT, Copyright 2026 Thinkscoop Technologies LLP. See `LICENSE`.

TDQS

A4.6/5.0

Scored across 12 tools

Disambiguation5/5

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.

Naming Consistency4/5

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.

Tool Count5/5

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.

Completeness5/5

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.

Maintenance

ActivitySlowing
ResponsivenessNo issues