Metadata-Version: 2.4
Name: meridian-mcp
Version: 0.6.5
Summary: Meridian — Local-first AI compliance scanner. DPDPA 2023 · RBI FREE-AI · SEBI AI/ML · EU AI Act. Works with any LLM provider. AST-level code analysis across Python, TypeScript, Go, Java.
Project-URL: Homepage, https://meridiancompliance.framer.website
Project-URL: Repository, https://github.com/KNambiarDJsc/Meridian
Project-URL: Issues, https://github.com/KNambiarDJsc/Meridian/issues
License: Apache-2.0
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: fastapi>=0.111.0
Requires-Dist: fastmcp>=2.0
Requires-Dist: jinja2>=3.1
Requires-Dist: litellm>=1.40
Requires-Dist: networkx>=3.0
Requires-Dist: pydantic>=2.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich-argparse>=1.4.0
Requires-Dist: scipy>=1.10
Requires-Dist: tenacity>=8.0
Requires-Dist: tree-sitter-go>=0.23
Requires-Dist: tree-sitter-java>=0.23
Requires-Dist: tree-sitter-javascript>=0.23
Requires-Dist: tree-sitter-python>=0.23
Requires-Dist: tree-sitter-typescript>=0.23
Requires-Dist: tree-sitter>=0.23
Requires-Dist: typer>=0.12
Requires-Dist: uvicorn>=0.30.0
Provides-Extra: all-providers
Requires-Dist: anthropic>=0.40; extra == 'all-providers'
Requires-Dist: boto3>=1.34; extra == 'all-providers'
Requires-Dist: groq>=0.9; extra == 'all-providers'
Requires-Dist: openai>=1.40; extra == 'all-providers'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.40; extra == 'anthropic'
Provides-Extra: bedrock
Requires-Dist: boto3>=1.34; extra == 'bedrock'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: groq
Requires-Dist: groq>=0.9; extra == 'groq'
Provides-Extra: openai
Requires-Dist: openai>=1.40; extra == 'openai'
Provides-Extra: pdf
Requires-Dist: playwright>=1.40; extra == 'pdf'
Description-Content-Type: text/markdown

<p align="center">
  <img src=".github/brand/logo-full.svg" alt="Meridian — AI Compliance Intelligence" width="720">
</p>

# Meridian

**Compliance Intelligence for AI startups.**
Meridian scans a repository deterministically, has one LLM call reason about what your business actually does, then deterministically resolves which of 17 real regulatory frameworks apply and produces an evidence-cited compliance report — DPDPA 2023, RBI FREE-AI, SEBI AI/ML, EU AI Act, GDPR, PCI DSS, SOC 2, CERT-In, and more. It answers the questions a compliance engineer would if they sat down with your CTO: **what applies, why, what's already verified, what's missing, and what to do next** — never a 1,445-row violation dump. By Karthik Nambiar

> Meridian provides automated compliance assessments and recommendations, not legal advice. Final compliance determinations should be reviewed by qualified legal, compliance, or security professionals where required. See [V1_SCOPE.md](V1_SCOPE.md) for the full V1 scope, data-handling details, and explicit non-goals.

[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-0F2A4A.svg)](https://www.python.org/downloads/)
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-0F2A4A.svg)](LICENSE)
[![Zero telemetry](https://img.shields.io/badge/telemetry-zero-0B7A4B.svg)](#privacy)

---

## How it works

Meridian is **one assessment pipeline**, not a deterministic scanner with an optional LLM bolted on. Exactly one LLM call happens per assessment — everything before and after it is deterministic and evidence-cited:

```
Repository
  ↓ (deterministic — tree-sitter parsing, no LLM)
Discovery → IR → Repository Graph → Fact Extraction → Capability Detection → Evidence Ledger
  ↓
Repository Context   (aggregated tech stack / behavioral signals — no detection of its own)
  ↓
Repository Context Interpreter        ← the ONE LLM call
  ↓
Repository Understanding + up to 5 Clarification Questions
  ↓ (a human — or an AI client on your behalf — answers)
Business Profile                       (deterministic lookup from the answers, no LLM)
  ↓ (deterministic from here on — zero LLM calls)
Framework Recommendation  →  Framework Loader  →  Objective Applicability
  ↓
Scoped Control Verdicts  →  Framework Summaries  →  Report
```

If the Interpreter is already confident about your business context, it asks zero questions and the assessment completes immediately — no human interaction required. `--offline` skips the Interpreter entirely and evaluates all 1,445 controls across all 17 frameworks deterministically, no LLM/API key needed at all.

**The compliance database** (`database/meridian.db`) is 17 real frameworks / 1,445 controls / 50 objectives / 49 capabilities, all shipped as data — not hardcoded in Python.

---

## Installation

```bash
pip install meridian-mcp
python3 -m meridian.cli configure   # pick a provider, paste your API key — once
python3 -m meridian.cli scan .      # done
```

`python3 -m meridian.cli ...` works identically on every OS with zero setup, because it never depends on the `meridian` console script being discoverable on `PATH` — only on `python3` itself, which is already guaranteed the moment `pip` ran successfully. If your shell already has the `meridian`/`meridian-mcp` commands on `PATH` (most installs do), you can drop the `python3 -m meridian.cli` prefix and just run `meridian configure` / `meridian scan .` directly.

If `meridian configure` reports "command not found" even though `pip install` succeeded, that's a `PATH` issue, not a broken install — pip's console script lands in a folder that isn't always on `PATH` by default (especially on macOS without a venv). The `python3 -m meridian.cli` form above sidesteps it entirely; [pipx](https://pipx.pypa.io) (`pipx install meridian-mcp`) is the more permanent fix, since it also isolates meridian-mcp's dependencies from anything else already installed.

The compliance database and all runtime metadata ship **inside the package** and are copied to `~/.meridian/meridian.db` automatically on first use. Nothing else to set up.

Installing gives you three console scripts on your `PATH` (once it resolves):

| Command | What it runs |
|---|---|
| `meridian` | The interactive CLI (`scan` / `report` / `compare` / `profile` / `configure`) |
| `meridian-ci` | Identical to `meridian` — same Typer app, kept as a separate alias for CI pipeline clarity |
| `meridian-mcp` | The MCP server (11 tools) for Claude Desktop / Cursor / Windsurf / any MCP client |

Optional extra: `pip install 'meridian-mcp[pdf]'` for PDF export (Playwright).

**From source (contributors):**

```bash
git clone https://github.com/KNambiarDJsc/Meridian.git
cd Meridian
python -m venv .venv
.venv\Scripts\activate        # Windows
source .venv/bin/activate     # macOS / Linux
pip install -e ".[dev]"
```

A source checkout resolves the database and metadata from the repo's own `database/` and `data/` directories automatically — same zero-flag commands, no copying either way. `--db-path` / `MERIDIAN_DB_PATH` still exist for pointing at a non-default database deliberately.

---

## Configure an LLM (first run only)

`meridian scan` needs an LLM for the one mandatory Interpreter call. On first run, if no provider is already configured, an interactive wizard walks you through it:

```
$ meridian scan .

No AI model configured.

Select Provider

1. OpenAI
2. Anthropic
3. Google Gemini
4. OpenRouter
5. Groq
6. Azure OpenAI
7. Show all providers

Enter a number: 2
```

("Show all providers" expands the list to all 15 — Ollama, AWS Bedrock, Vertex AI, Fireworks AI, Together AI, DeepSeek, xAI, Mistral, Cohere. Every provider stays fully supported; the short list is just the first screen.)

```

Select Model
  (live list from litellm — the models actually available for that provider today)

1. claude-haiku-4-5
2. claude-opus-4-8
3. claude-sonnet-4-6
...
21. Custom (enter a model name)

Enter a number: 2

Enter API Key: ****************

Save this configuration? [Y/n]: y
Saved to /home/you/.meridian/config.toml
```

The wizard writes `provider`/`model`/`api_key` to `~/.meridian/config.toml` (never inside the scanned repository) so it never runs again. **It's skipped entirely if you already have a provider's API key set as an environment variable** (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GROQ_API_KEY`, etc. — see the full table below) or an existing `~/.meridian/config.toml` — Meridian never asks twice, and never re-asks if credentials are already present.

**To switch providers/models, fix a broken saved config, or just re-run the wizard on demand**, either command forces it regardless of what's already configured:

```bash
meridian configure                    # standalone — just (re)runs the wizard, then exits
meridian scan . --reconfigure         # runs the wizard first, then proceeds with the scan
```

If you don't want an LLM at all, use `--offline` (below) and skip this section entirely.

---

## CLI commands

### `meridian scan` — run a full assessment (the main command)

```bash
meridian scan <repository_path> [OPTIONS]
```

| Flag | Default | Meaning |
|---|---|---|
| `--db-path TEXT` | `~/.meridian/meridian.db` | Path to `meridian.db` |
| `--offline` | off | Skip the LLM entirely — deterministic scan only, all 1,445 controls, no questions asked |
| `--format TEXT` | `markdown` | Report format once the assessment completes: `json`, `markdown`, `sarif`, `html`, `pdf` |
| `--output TEXT` / `-o` | stdout | Write the report to a file instead of printing it (required for `pdf`) |
| `--fail-on TEXT` | `none` | Exit non-zero if any FAILED (code-verified) finding meets this severity: `none`, `low`, `medium`, `high`, `critical` — Needs Documentation/Attestation never trips it |
| `--reconfigure` | off | Force the provider/model/API key wizard to run first, even if already configured |

**Full interactive assessment** (asks clarification questions, produces a scoped report against only the frameworks that actually apply):

```bash
meridian scan .
```

You'll see a repository summary, then each clarification question with numbered options:

```
Question 1 of 3
Does the application store personal data?
1. Yes
2. No
3. Unsure
Enter a number (or press Enter to skip): 1
```

Answer each one (or press Enter to skip — that field just stays unanswered, never guessed), and the assessment completes: Framework Recommendation → Framework Loader → Objective Applicability → scoped verdicts → report, printed to stdout as markdown.

**Deterministic scan, no LLM, no questions, all 1,445 controls** (same as any earlier Meridian version's behavior):

```bash
meridian scan . --offline
# or, equivalently:
MERIDIAN_OFFLINE=1 meridian scan .
```

**Save the report to a file instead of printing it:**

```bash
meridian scan . --format json --output report.json
meridian scan . --format pdf --output report.pdf
```

**CI/CD gate — fail the build on Critical violations:**

```bash
meridian scan . --offline --fail-on critical
echo $?   # 0 = clean, 1 = violations at/above threshold found, 2 = bad arguments
```

```yaml
# .github/workflows/compliance.yml
- name: Run Meridian compliance gate
  run: meridian scan . --offline --fail-on critical
```

### `meridian report` — regenerate a report without re-answering questions

Always deterministic-only (re-runs the scan for full evidence fidelity, no LLM/Interpreter involved) — useful once you already know which frameworks matter and just want the full 1,445-control report:

```bash
meridian report <repository_path> [--format markdown|json|sarif|html|pdf] [--output FILE] [--db-path PATH]
```

### `meridian compare` — diff two historical scans

```bash
meridian compare <repository_path> <older_scan_hash> <newer_scan_hash>
```

Every `meridian scan` prints a `Scan hash:` you can use here. Shows newly-violated controls, fixed controls, and capability status changes.

### `meridian profile` — read the last scan's Repository Intelligence Profile

```bash
meridian profile <repository_path>
```

### `meridian configure` — (re)run the provider/model/API key wizard on demand

```bash
meridian configure
```

Runs the same wizard `meridian scan` runs automatically on first use, but unconditionally — even if a provider is already configured — so you can switch providers/models or overwrite a broken saved config. Equivalent to `meridian scan <path> --reconfigure` except it doesn't also run a scan afterward.

Reads persisted history — does not scan on its own; run `meridian scan` (with or without `--offline`) first.

---

## MCP server (Claude Desktop, Cursor, Windsurf, Antigravity)

`meridian-mcp` exposes 11 tools. The two that matter for the full assessment flow:

- **`start_scan(repository_path)`** — runs the deterministic scan + the Interpreter. Returns either a completed assessment (if the LLM was already confident) or a `session_id` + `repository_summary` + `questions` for the calling AI client to ask the human.
- **`continue_scan(session_id, answers)`** — resume with `{question_id: answer_text}`, completes the assessment and returns the scoped report.

Plus `scan_repository`/`generate_report` (the deterministic-only, no-LLM path), `repository_profile`, `technology_inventory`, `risk_summary`, `repository_summary`, `compare_scans`, `explain_control`, and `ai_governance_summary`.

### Claude Desktop (`%APPDATA%\Claude\claude_desktop_config.json`)

```json
{
  "mcpServers": {
    "meridian": {
      "command": "meridian-mcp",
      "env": {
        "ANTHROPIC_API_KEY": "YOUR_KEY_HERE",
        "MERIDIAN_DB_PATH": "D:\\meridian-mcp\\database\\meridian.db"
      }
    }
  }
}
```

### Cursor / Windsurf / Antigravity (`~/.cursor/mcp.json`, etc.)

```json
{
  "mcpServers": {
    "meridian": {
      "command": "meridian-mcp",
      "env": {
        "ANTHROPIC_API_KEY": "YOUR_KEY_HERE",
        "MERIDIAN_DB_PATH": "/absolute/path/to/database/meridian.db"
      }
    }
  }
}
```

Use the absolute path to `meridian-mcp` if it isn't globally on your `PATH` (e.g. inside a venv: `/path/to/.venv/Scripts/meridian-mcp.exe` on Windows, `/path/to/.venv/bin/meridian-mcp` on macOS/Linux).

---

## REST API + background worker

`src/meridian/api/app.py` (FastAPI) exposes `POST /scan`, `POST /scan/start` + `POST /scan/continue` (the same two-call assessment protocol as MCP), `POST /report`, `POST /compare`, `GET /findings`, `GET /controls`, `GET /profile`, plus `/admin/api-keys` and `/admin/audit-log`. It isn't installed as a console script — run it directly:

```bash
uvicorn meridian.api.app:app --host 0.0.0.0 --port 8000
```

Or via the bundled Docker image, which also supports a background worker mode for async scan jobs:

```bash
docker build -f deploy/docker/Dockerfile -t meridian .
docker run -p 8000:8000 -e MERIDIAN_DB_PATH=/data/meridian.db -v $(pwd)/database:/data meridian          # api mode (default)
docker run -e MERIDIAN_DB_PATH=/data/meridian.db -v $(pwd)/database:/data meridian python -m meridian.docker_entrypoint worker
```

The repo-root `Dockerfile` instead runs only `meridian-mcp` (the MCP server), for a minimal MCP-only image.

---

## Environment variables

| Variable | Default | Meaning |
|---|---|---|
| `MERIDIAN_HOME` | `~/.meridian` | Base directory for the compliance database default below |
| `MERIDIAN_DB_PATH` | `$MERIDIAN_HOME/meridian.db` | Path to the compliance database |
| `MERIDIAN_OFFLINE` | unset | Set to `1`/`true`/`yes` to force the deterministic-only path (same as `meridian scan --offline`) |
| `MERIDIAN_INTERPRETER_MODEL` | resolved from `~/.meridian/config.toml` or provider default | Model for the one mandatory LLM call |
| `MERIDIAN_EVALUATOR_MODEL`, `MERIDIAN_CRITIC_MODEL` | provider defaults | Reserved for the optional LLM-augmentation layer (`evaluator/`/`critic/`) — not wired into any scan path today |
| `MERIDIAN_MAX_CONCURRENT` | `5` | Max concurrent LLM requests |
| `MERIDIAN_RPM_LIMIT`, `MERIDIAN_TPM_LIMIT` | provider-inferred | Override the auto-detected rate limits |
| `MERIDIAN_API_PORT`, `MERIDIAN_API_WORKERS` | `8000`, `1` | REST API server (Docker `api` mode) |
| `MERIDIAN_WORKER_COUNT` | `1` | Background worker count (Docker `worker` mode) |
| Provider keys | — | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `GROQ_API_KEY`, `OPENROUTER_API_KEY`, `AZURE_API_KEY`, `AWS_ACCESS_KEY_ID`+`AWS_SECRET_ACCESS_KEY` (Bedrock), `GOOGLE_APPLICATION_CREDENTIALS` (Vertex AI), `FIREWORKS_AI_API_KEY`, `TOGETHER_AI_API_KEY`, `DEEPSEEK_API_KEY`, `XAI_API_KEY`, `MISTRAL_API_KEY`, `COHERE_API_KEY` — any one of these, if set, skips the setup wizard |

---

## Project structure

```
src/meridian/
├── cli.py                     # meridian / meridian-ci — scan, report, compare, profile
├── cli_setup.py                # Interactive LLM setup wizard + clarification-question prompting
├── config.py                    # Provider/model config, live litellm model catalogue, ~/.meridian/config.toml
├── engine.py                     # MeridianEngine — the one orchestration layer every transport calls
├── scan_state.py                  # ScanPaused / ScanCompleted / ScanFailed — the engine's execution contract
├── scan_orchestrator.py            # run_scan() / run_and_persist_scan() — the M1-M6 deterministic pipeline
│
├── discovery.py, parsers/, ir/, ir_builder.py, graph/     # Repository → IR → Repository Graph
├── facts/, detectors/, evidence/, inventory/               # Fact extraction → capability detection → evidence
├── compliance/, verdicts/                                    # meridian.db access, control verdict resolution
├── profile/, ai_governance/                                    # Repository Intelligence Profile, AI-BOM/governance
│
├── context/, interpreter/, assessment/                     # Sprint 1-2: Repository Context + the one LLM call
├── framework_recommendation/, framework_loader/              # Sprint 2-3: which frameworks apply
├── objective_applicability/                                    # Sprint 4: which objectives/controls apply
│
├── report/                     # ReportContext + markdown/json/sarif/html/pdf exporters
├── scan_ledger/, ledger.py      # Scan history, comparison, tamper-evident audit chain
├── search/, embeddings/          # Semantic search index (rebuilt explicitly, not on every scan)
│
├── mcp/server.py                # FastMCP server, 11 tools
├── api/                           # FastAPI REST server
└── workers/                        # Background async scan job queue
```

`evaluator/`, `critic/`, `augmentation/`, `clustering/`, `cache_engine/`, `annotation/` are real, tested subsystems not currently wired into any scan path — see `CLAUDE.md` for the full picture of what's live vs. built-but-disconnected.

---

## Running tests

```bash
pytest tests/ -v
pytest tests/test_cli.py -v                    # a single file
pytest tests/test_cli.py::test_scan_real_counts -v   # a single test
```

Most e2e tests need the local `database/meridian.db` (present in the repo) — they skip cleanly if it's missing. A handful of older tests additionally expect a real Flask checkout at `/tmp/flask-repo` and skip without it.

---

## Privacy

Meridian is local-first, and the claim is verifiable in the code — not marketing copy:

- **Your code never leaves your machine.** The entire scan pipeline (discovery, parsing, fact extraction, capability detection, evidence, verdicts, reporting) runs locally against the bundled compliance database. Meridian has no servers in any code path — there is nowhere to upload your repository *to*.
- **Zero telemetry.** Meridian sends no usage data anywhere, and LiteLLM's own telemetry is explicitly disabled in code (`litellm.telemetry = False` in `evaluator/provider.py`).
- **Keys never leave your machine.** API keys are read from your environment or `~/.meridian/config.toml` and passed directly to the provider SDK via [litellm](https://github.com/BerriAI/litellm) — no Meridian-run proxy, no logging of credentials.
- **Exactly one LLM call per assessment**, made directly from your machine to the provider you chose, with your own key. Every control verdict, every framework applicability decision, every objective evaluation is deterministic — nothing about compliance reasoning is ever sent to or decided by an LLM.
- **`--offline` needs no network access and no API key at all.**
- No other network access exists anywhere in the codebase beyond the one LLM call above and the one-time package install itself — grep-verified, not just asserted.

---

## License

Apache 2.0 — see [LICENSE](LICENSE). All 17 frameworks are available unconditionally; there is no tiered/licensed feature gate in the current codebase.

---
<!-- mcp-name: io.github.KNambiarDJsc/meridian-mcp -->
