Metadata-Version: 2.4
Name: ciphra-mcp
Version: 0.1.0
Summary: Python MCP server for Ciphra. Lets AI coding agents call Ciphra's secret scanner via the Model Context Protocol.
Project-URL: Homepage, https://github.com/sanjayselvam31/ciphra
Project-URL: Repository, https://github.com/sanjayselvam31/ciphra
Project-URL: Issues, https://github.com/sanjayselvam31/ciphra/issues
Author: Sanjay Selvam
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,ciphra,mcp,scanner,secrets,security
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Requires-Python: >=3.11
Requires-Dist: mcp>=1.0.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# ciphra-mcp

Python MCP server exposing Ciphra's secret scanner to AI agents.

## What this is

The agent-facing layer for [Ciphra](../README.md). The actual scanning is done by the TypeScript CLI at the repo root; this Python project spawns the CLI as a subprocess and translates between MCP's JSON-RPC protocol and Ciphra's JSON output. With this server registered, agents like Claude Code and Cursor can scan a codebase, validate a key, or audit git history without the user typing CLI commands.

## Prerequisites

- **Node 20+** — needed for the underlying `ciphra` CLI, which this MCP server shells out to
- **Python 3.11+** — for the MCP server itself
- **[uv](https://github.com/astral-sh/uv)** (recommended) or `pip + venv`
- **`ciphra` on `$PATH`.** The MCP server resolves the CLI via `shutil.which("ciphra")`, so it must be installed globally:

  ```bash
  npm install -g ciphra
  ```

  If you get an `EACCES` error on `npm install -g`, your npm prefix is root-owned. The cleanest fix:

  ```bash
  mkdir -p ~/.npm-global
  npm config set prefix ~/.npm-global
  echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc
  source ~/.zshrc
  npm install -g ciphra
  ```

## Installation

```bash
uvx ciphra-mcp                    # ephemeral; runs the published wheel on demand
```

That's it — `uvx` downloads the wheel from PyPI on first invocation, then runs the entry point. No clone required.

If you'd rather have it permanently installed in a project-local venv:

```bash
uv pip install ciphra-mcp
```

### Building from source (contributors)

```bash
cd /path/to/ciphra
npm install && npm run build      # build the TS CLI

cd mcp-server
uv sync --extra dev               # creates .venv, installs deps
```

(pip alternative: `python3.11 -m venv .venv && source .venv/bin/activate && pip install -e ".[dev]"`)

## Running the server

**Standalone (sanity check that it launches):**

```bash
uv run ciphra-mcp
```

The server speaks MCP over stdio and isn't useful interactively. Send EOF (`Ctrl-D`) to exit. Most of the time you won't run this directly — the MCP client launches it for you.

**As an MCP server in Claude Code:**

Add to `~/.claude.json` (create the file if it doesn't exist):

```json
{
  "mcpServers": {
    "ciphra": {
      "command": "uvx",
      "args": ["ciphra-mcp"]
    }
  }
}
```

Restart Claude Code. The four Ciphra tools become available to the agent automatically.

**As an MCP server in Cursor:**

Add the same block to `~/.cursor/mcp.json`. Restart Cursor.

**Contributor / local-development alternative.** If you're running from a source checkout (the "Building from source" path above) instead of the published wheel, point the MCP client at your local venv:

```json
{
  "mcpServers": {
    "ciphra": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/ciphra/mcp-server", "run", "ciphra-mcp"]
    }
  }
}
```

## The four MCP tools

- **`scan_directory`** — the primary tool for "is this codebase secure?" / "are there leaked keys?" prompts. Scans a directory and (by default) its git history across all 10 supported services. Validation is opt-in. Example: *"Scan this directory for leaked keys."*

- **`check_specific_service`** — use when the user has named a single service of concern. Faster than `scan_directory` because only that service's detectors run, and defaults to live validation since scope is narrow. Example: *"I'm worried about Stripe keys in this codebase."*

- **`scan_git_history`** — scans only the commit history (current files are not touched). For auditing keys that were committed and later removed but remain recoverable from history. Example: *"Did I ever commit an AWS key I later deleted?"*

- **`validate_key`** — checks whether a specific key value is currently active against its service's live API. For "has this key value been used in my repo?" questions, agents should grep first; this tool is for one-shot live-status checks. Example: *"Is `sk_test_abc123` a real Stripe key?"*

The exact descriptions live in [src/ciphra_mcp/server.py](src/ciphra_mcp/server.py). Agents read those directly — when in doubt about how a prompt routes, that file is the source of truth.

## Running tests

```bash
uv run pytest
```

The suite is full integration: tests spawn the real CLI subprocess. A `pytest_sessionstart` hook checks that `dist/cli/index.js` is current relative to `src/**/*.ts`; if any TS file is newer, the session aborts before collection with the offending paths and an instruction to run `npm run build` from the repo root.

Set `CIPHRA_SKIP_STALENESS_CHECK=1` to bypass — useful in CI where the build is guaranteed to have already run.

## Layout

```
src/ciphra_mcp/
  server.py         FastMCP setup, four @mcp.tool registrations
  ciphra_client.py  Async subprocess wrapper around the TS CLI
  types.py          TypedDicts mirroring the CLI JSON schema (v1.0)
tests/
  conftest.py       Staleness check + EXPECTED_TOOL_NAMES constant
  test_*.py         Integration tests (33 in total)
scripts/
  verify_handshake.py            Manual MCP protocol handshake check
  verify_*.py                    Per-tool one-shot verification scripts
```

## Security notes

- **Validated keys hit live third-party APIs.** Defaults: `scan_directory` and `scan_git_history` are validate=OFF; `check_specific_service` is validate=ON (the user has narrowed scope to one service, so the cost is bounded); `validate_key` always sends. Don't validate keys you don't own or haven't been explicitly asked about — the call is logged at the third-party service.
- **Key values are never logged or returned in tool output.** Findings include a redacted preview (first/last 4 chars); validation results contain only status and reason.
- **`validation: invalid` is not a safety signal.** It means the key isn't currently authenticating — but it was exposed in the codebase, so the leak still happened. Rotate regardless.

## Troubleshooting

- **`ciphra-mcp: command not found`** — run `uv sync --extra dev` from `mcp-server/`, or activate the venv if using pip.
- **"TypeScript source is newer than dist/cli/index.js"** — run `npm run build` from the repo root.
- **Agent says no Ciphra tools are available** — the MCP client likely cached an older state of the server (e.g. from before tools were wired up). Restart the client. New tool descriptions also require a restart — the running Python process captures the description strings at import time.
- **Tools appear but calls fail with `CiphraNotFoundError`** — the MCP config points at the wrong directory, or `npm run build` hasn't been run. Verify by running `uv run ciphra-mcp` from a terminal in `mcp-server/`; it should launch silently and wait on stdin.
- **"Server has 0 tools"** in `verify_handshake.py` — almost always a stale running process. Check that `mcp-server/src/ciphra_mcp/server.py` has the four `@mcp.tool(...)` decorators and reload your client.
