# @ship-safe/mcp

A [Model Context Protocol](https://modelcontextprotocol.io) server for ShipSafe, the independent verifier for AI-built apps: your AI coding agent (Cursor, Claude Code, Claude Desktop, Windsurf, …) scans the code it writes for security vulnerabilities — **in-loop, without leaving the editor**.

It runs ShipSafe's fast local pattern scan for free (secrets, injection, broken auth/IDOR, misconfig) plus a **dependency CVE scan** of your lockfiles (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `requirements.txt`, `go.sum`, `Gemfile.lock`) via the OSV database. With a login it also runs **AI deep analysis** (a free account includes one AI scan), and on a monthly plan it can generate a one‑paste fix prompt. Your code is never stored.

## Tools

| Tool | What it does | Auth |
|------|--------------|------|
| `shipsafe_scan` | Scan a directory; returns plain‑English findings with the exact fix for each, plus structured output (see below). | Free (local). AI analysis needs Growth/Shield. |
| `shipsafe_fix_prompt` | Scan, then return one paste‑ready prompt that fixes everything, tailored to the detected AI builder. | Growth / Shield |
| `shipsafe_status` | Show login state, plan, and remaining AI scan quota. | — |
| `shipsafe_login` | Log in from the editor: call once for a browser URL + code, then again with the returned `device_code` to finish. | — |

Secrets that show up in findings are masked (`[REDACTED]`) before anything is echoed back to the agent, so a model can't quote a real credential into its transcript.

### `shipsafe_scan` inputs

| Input | Type | Purpose |
|-------|------|---------|
| `path` | string | Directory to scan (defaults to cwd). |
| `severity` | `critical`\|`high`\|`medium`\|`low` | Only return findings at or above this severity. |
| `ai` | boolean | Run AI deep analysis (needs a login). On by default on paid plans; a free account includes one AI scan, so pass `true` to use it. |
| `paths` | string[] | Scan only these files/dirs (inside the project) — e.g. the files you just edited. Fast inner loop. |
| `changedOnly` | boolean | Scan only files changed vs git HEAD + new untracked files. Falls back to a full scan if not a git repo. |
| `upload` | boolean | Save the scan to your ShipSafe dashboard (needs login) and return a shareable `dashboardUrl`. Off by default. |

### Structured output

Alongside the human‑readable report, `shipsafe_scan` returns machine‑readable `structuredContent` an agent can branch on:

- `clean` (boolean) and `counts` (by severity) — a greppable pass/fail, so you never have to parse prose.
- `findings[]` — each with `key`, `severity`, `file`, `line`, `cwe`, `plainEnglish`, `fixDescription`, `fixSuggestion`.
- `scanned` — `{ mode: "full" | "targeted", sourceFiles, dependencyFiles }`.
- `diff` (full‑project scans only) — `{ resolved, stillOpen, introduced }` vs your previous scan of the same directory, so a `scan → fix → re-scan` loop can confirm a fix actually worked. The diff state is kept locally under `~/.shipsafe/mcp-history` and never leaves your machine.

Failures (no source files, generation errors, not logged in) are returned with `isError: true`, so "couldn't run" is never mistaken for "ran clean".

## How accurate is it?

Published, including the misses — the numbers below come from a public benchmark
of **1,147 labelled cases** (569 vulnerable, 578 clean twins), scored with a
per-category confusion matrix. Source of truth: `apps/web/src/lib/benchmark-measured.json`
(pattern-scan row) and `apps/web/src/lib/benchmark-figures.ts` (AI-pass row), regenerated
by `packages/scanner/__tests__/eval-corpus.test.ts` — this table is a snapshot, not a
second source; check those files before trusting an old copy of this README.

| Layer | Precision | Recall |
|-------|-----------|--------|
| Pattern scan (free) | 92.5% | 47.8% |
| With AI analysis | 72.7% | 84.5% |
| With AI, held-out slice | — | 82.0% |

The free pattern layer is deliberately high-precision and low-recall: it is
tuned to almost never cry wolf, which means it misses more than half of what a
deep scan finds. The AI pass roughly doubles recall and gives up some precision
to do it. Neither layer certifies that an app is secure, and no scanner can.

Full method, per-category breakdown and every miss: <https://ship-safe.co/benchmark>

## Login (for AI analysis)

The free local + dependency scan works with no login and no limit. AI deep analysis needs a login: a free account includes one AI scan, and the monthly plans include more AI scans plus fix prompts ([pricing](https://ship-safe.co/pricing)). Log in either way:

- **From the editor:** ask your agent to log in — it calls the `shipsafe_login` tool, which gives you a browser URL + code and finishes once you authorize.
- **From a terminal:** `npx @ship-safe/cli login`.

Both write `~/.shipsafe/token.json`, which this MCP server reads, so a single login covers the CLI and the MCP.

## Setup

### Cursor — `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global)

```json
{
  "mcpServers": {
    "shipsafe": { "command": "npx", "args": ["-y", "@ship-safe/mcp"] }
  }
}
```

### Claude Code

```bash
claude mcp add shipsafe -- npx -y @ship-safe/mcp
```

### Claude Desktop — `claude_desktop_config.json`

```json
{
  "mcpServers": {
    "shipsafe": { "command": "npx", "args": ["-y", "@ship-safe/mcp"] }
  }
}
```

Then ask the agent: *"scan this project with ShipSafe and fix what it finds."*

## Configuration

| Env var | Default | Purpose |
|---------|---------|---------|
| `SHIPSAFE_API_URL` | `https://ship-safe.co` | Point at a local/staging backend (e.g. `http://localhost:3000`). |

## Local development

```bash
pnpm install
pnpm --filter @shipsafe/shared --filter @shipsafe/scanner build
pnpm --filter @ship-safe/mcp build
# run the built server directly (stdio):
node apps/mcp/dist/index.js
```
