Python MCP server for Ciphra. Lets AI coding agents call Ciphra's secret scanner via the Model Context Protocol.
Project description
ciphra-mcp
Python MCP server exposing Ciphra's secret scanner to AI agents.
What this is
The agent-facing layer for Ciphra. 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
ciphraCLI, which this MCP server shells out to -
Python 3.11+ — for the MCP server itself
-
uv (recommended) or
pip + venv -
ciphraon$PATH. The MCP server resolves the CLI viashutil.which("ciphra"), so it must be installed globally:npm install -g ciphra
If you get an
EACCESerror onnpm install -g, your npm prefix is root-owned. The cleanest fix: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
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:
uv pip install ciphra-mcp
Building from source (contributors)
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):
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):
{
"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:
{
"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 thanscan_directorybecause 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: "Issk_test_abc123a real Stripe key?"
The exact descriptions live in 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
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_directoryandscan_git_historyare validate=OFF;check_specific_serviceis validate=ON (the user has narrowed scope to one service, so the cost is bounded);validate_keyalways 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: invalidis 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— runuv sync --extra devfrommcp-server/, or activate the venv if using pip.- "TypeScript source is newer than dist/cli/index.js" — run
npm run buildfrom 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, ornpm run buildhasn't been run. Verify by runninguv run ciphra-mcpfrom a terminal inmcp-server/; it should launch silently and wait on stdin. - "Server has 0 tools" in
verify_handshake.py— almost always a stale running process. Check thatmcp-server/src/ciphra_mcp/server.pyhas the four@mcp.tool(...)decorators and reload your client.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ciphra_mcp-0.1.0.tar.gz.
File metadata
- Download URL: ciphra_mcp-0.1.0.tar.gz
- Upload date:
- Size: 13.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0602805b0aafc076e2606f56766857855dbda753906c02eb4a46e7304c09aad0
|
|
| MD5 |
067f5343271f64761324dcd40c66e5b2
|
|
| BLAKE2b-256 |
060a99e9c834a6753773e4e59f02fb294d226a15934953f2a00e92a92813c14e
|
File details
Details for the file ciphra_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ciphra_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c12a4796d70b05fc119181e5de3b4dc6504d68b09e90cd346567ed564034320
|
|
| MD5 |
33aa4182c82d8e076c0ffa903db5a7c0
|
|
| BLAKE2b-256 |
f13779008a4d9935a782c45cbb948a608266cc598b4df1caf04ae472088c587e
|