jev-mcp
September 21, 2026 · View on GitHub
An MCP server that turns Cursor's "I think I'm done" into a checked decision. It collects git and test signals, asks TypeSafe Jev a set of narrow questions, and returns a typed verdict: fix, ask, or done.
The routing decision is made by policy code in this repository. Jev answers atomic questions about the state; it does not choose the action.
| Name | |
|---|---|
| PyPI | mcp-jev-mcp |
| CLI | jev-mcp |
Quick start
pipx install mcp-jev-mcp
jev-mcp key add <YOUR_TYPESAFE_API_KEY>
jev-mcp key status
Then add the MCP server to Cursor (~/.cursor/mcp.json or the project's .cursor/mcp.json):
{
"mcpServers": {
"jev-mcp": {
"type": "stdio",
"command": "jev-mcp",
"args": ["serve"]
}
}
}
Reload MCP in Cursor, then ask the agent to call health.
Requirements
- Python 3.11 or newer
giton PATH- A TypeSafe API key
API key
Resolution order:
TYPESAFE_API_KEYin the environment — use this in CI.<JEV_MCP_HOME>/credentials.yaml, written byjev-mcp key add.
JEV_MCP_HOME defaults to ~/.jev-mcp.
jev-mcp key add <API_KEY> # verifies against TypeSafe, then stores
jev-mcp key status # source plus a masked hint, never the key
jev-mcp key remove
On Linux and macOS the file is written with mode 0600. On Windows it is protected
only by your user profile ACL, so prefer the environment variable on a shared machine.
MCP tools
| Tool | What it does |
|---|---|
collect_git(project_root, base_ref?, staged_only?, max_diff_bytes?) | Branch, changed files, and a diff budgeted per file so no hunk is cut in half |
run_tests(project_root, command?, timeout_s?) | Runs the detected or supplied test command; a non-zero exit code comes back as data |
decide(goal, git?, tests?, profile?, extra?) | Asks Jev, applies policy, returns fix / ask / done with reasons |
health(project_root?, probe?) | Key source, git availability, detected test command |
describe() | The live question set, policy rules, and profiles |
The tools are stateless: pass the collect_git and run_tests payloads straight into decide.
Recommended workflow
- The agent implements the change.
collect_gitandrun_tests.decidewith the user's goal and both payloads.- Obey the verdict —
fixkeeps working,askgoes to the user,donemay finish.
Add a project rule requiring step 4 before any completion claim.
Profiles
| Profile | Behavior |
|---|---|
default | The nine policy rules as written |
strict | Also asks when code changed with no test signal, or when Jev's cross-check confidently disagrees with a done |
ci | done requires a test run that exited zero |
Headless gate
jev-mcp gate --goal "add retry to the uploader" --project-root . --profile ci --json
| Exit code | Meaning |
|---|---|
| 0 | done |
| 1 | fix |
| 2 | ask |
| 3 | tool error |
Usable from a pre-push hook or a CI job.
Configuration
<JEV_MCP_HOME>/config.yaml, with environment variables taking precedence.
See docs/superpowers/specs/2026-09-21-jev-mcp-design.md section 4 for every field.
git:
max_diff_bytes: 524288
max_file_diff_bytes: 65536
tests:
default_timeout_s: 600
projects:
- match: "pyproject.toml"
command: ["poetry", "run", "pytest", "-q"]
jev:
model: jev-1.13
max_retries: 2
decision:
default_profile: default
Security
- The key never travels through an MCP tool; key management is CLI-only.
- Diffs and test output pass through a redactor before they reach Jev or the logs.
- Subprocesses run through an argument vector; there is no shell interpolation.
- Your diff and test output are sent to the TypeSafe API. Treat that as you would any third-party code analysis service, and read their terms.
serve --transport httpbinds to localhost and has no authentication. It is for local debugging only.
Development
poetry install
poetry run pytest -v
poetry run ruff check src tests
poetry run jev-mcp serve --transport http
License
MIT