jev-answers
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@jev-answersyes/no: is src/auth.ts safe to merge as-is?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
jev-answers
A small MCP server and CLI that sends files and typed questions to TypeSafe's Jev decision model and returns the raw answer. Every request gets its own session folder that keeps the inputs, the exact request and the response.
Zero dependencies, plain Node.js (>= 22), no build step.
One MCP tool,
jev_ask, for Claude Code, Codex, OpenCode, Cursor, Claude Desktop and any other MCP client.A thin pipe: it never interprets answers. No thresholds, no verdicts, no "flags". You get the provider's response body unchanged.
It does not run git or any other command. If you want a diff reviewed, write the diff to a file and pass the path.
Jev answers typed questions with probabilities instead of prose:
type | question | answer |
| a yes/no question | probability that the answer is YES (0.5 means it cannot tell) |
| pick one option | the chosen option plus a probability per option |
| position on ordered levels | a number between 0 and (levels - 1), plus probabilities |
This project is not affiliated with TypeSafe AI.
How it works
Each call runs three independent stages. Each stage reads only what the previous one wrote into the session folder.
collect -> build -> send~/.jev-answers/sessions/20260930-164512-payment-review-7f3a/
input.json the call arguments, exactly as received
inputs/ collected copies of every file (relative layout kept; outside files under _external/)
manifest.json what was collected and what was skipped, with sizes and sha256
request.json the exact body that was sent (never contains the API key)
response.json the provider's raw response
error.json only on failure: {stage, type, message, details}
meta.json id, label, provider, model, status, token estimate, timings, HTTP statussessions/latest is a symlink to the newest session.
Related MCP server: jevcore-mcp
Install
Run the setup wizard. It asks for your provider, API key and model, writes the config file, and offers to register the server with the MCP clients it finds on your machine.
npx -y jev-answers setup
# or the latest main branch straight from GitHub
npx -y github:AmooEbrahim/jev-answers setup
# or from a clone
node bin/jev-answers.js setupnpx caches packages. To pick up a new release, run npx -y jev-answers@latest --version once.
Get a key at console.typesafe.ai (TypeSafe direct) or openrouter.ai/keys (OpenRouter). The key is stored in the config file (mode 0600), so your client configs need no environment variables.
Switching provider drops the stored key, model and base URL, because they belong to the old provider; in --yes mode you must pass --api-key when you switch. Optional flags: --model, --home, --base-url, --skill claude,agents (install the agent skill).
Non-interactive:
jev-answers setup --provider typesafe --api-key "$KEY" --yes
jev-answers setup --provider typesafe --api-key "$KEY" --yes --register claude,codex,opencodeManual client configuration
Use whichever launch command fits: npx -y jev-answers serve, or /absolute/path/to/node /absolute/path/to/bin/jev-answers.js serve for a clone (setup writes the full path of the running Node). On Windows, setup prints the registration commands instead of running them.
Claude Code:
claude mcp add --scope user jev-answers -- npx -y jev-answers serveCodex:
codex mcp add jev-answers -- npx -y jev-answers serveor in ~/.codex/config.toml:
[mcp_servers.jev-answers]
command = "npx"
args = ["-y", "jev-answers", "serve"]OpenCode:
opencode mcp add --global jev-answers -- npx -y jev-answers serveor in ~/.config/opencode/opencode.json:
{
"mcp": {
"jev-answers": {
"type": "local",
"command": ["npx", "-y", "jev-answers", "serve"],
"enabled": true
}
}
}Cursor, Claude Desktop and other clients that use mcpServers:
{
"mcpServers": {
"jev-answers": {
"command": "npx",
"args": ["-y", "jev-answers", "serve"]
}
}
}If you prefer environment variables over the config file, add "env": {"JEV_ANSWERS_API_KEY": "..."} to the client entry. Note that some clients do not expand ${VAR} references; the server reports a clear config_error if it sees an unexpanded placeholder.
Configuration
Precedence, low to high: built-in defaults, config file, environment variables, the per-call model.
The config file is $JEV_ANSWERS_CONFIG if set, otherwise $XDG_CONFIG_HOME/jev-answers/config.json, otherwise ~/.config/jev-answers/config.json.
key | environment variable | default |
|
|
|
|
| per provider, see below |
|
|
|
|
| falls back to |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
base_url is the full endpoint URL:
TypeSafe:
https://api.typesafe.ai/v1/systemoneOpenRouter:
https://openrouter.ai/api/alpha/decisions(an alpha endpoint that may move).https://openrouter.ai/api/v1/systemoneis an alternative TypeSafe-compatible path you can set here.
Any gateway that speaks the same request format works too.
Check what is in effect with jev-answers config or jev-answers doctor.
The jev_ask tool
Input
{
"files": [
"/abs/path/app/Services/PaymentService.php",
{"path": "/tmp/review/change.diff", "label": "git diff of the change under review"},
"app/Http/Controllers/**/*.php"
],
"base_dir": "/abs/project/root",
"context": "Optional free text: the task, requirements, rules, notes.",
"questions": { "...": "see below" },
"label": "payment-review",
"model": "jev-latest"
}files: paths, directories, globs, or{path, label}. Relative paths resolve againstbase_dir(default: the server's working directory); absolute paths are safest.context: free text that is added to the state next to the files.At least one of
filesorcontextis required.questionsis required.Directories and globs (
**,*,?,[...],{a,b}) are expanded by the tool itself. Following the usual glob convention, both skip hidden entries (names starting with., and everything inside hidden directories) unless the pattern segment itself starts with a dot:.github/**/*.ymland**/.eslintrc*work,**/*.ymldoes not reach into.github. Hidden entries are listed inmanifest.json(a hidden directory once, not its contents). A*.mdpattern only looks as deep as the pattern is long, a trailing slash (src/,src/**/) means the directory itself, and an expansion that visits more than 20,000 entries fails withinvalid_inputso you can narrow it. Unreadable directories are skipped with reasonunreadable. Expansion skips any path inside.git,node_modules,vendor,dist,build,.next,.venv,venv,__pycache__,coverageor.jev-answers, plus binary files, secret files and symlinks (files and directories; they are never followed). Skipped files are listed inmanifest.jsonunderskippedwith a reason.A file you name explicitly is never skipped silently: if it is missing, binary, secret or too large, the call fails. An explicitly named symlink is allowed, but both the link and its target are checked against the secret-file patterns.
If nothing was collected and there is no
context, the call fails withinvalid_inputinstead of sending an empty state.Unknown top-level fields (for example a
filetypo) are rejected withinvalid_input.labelbecomes part of the session folder name.modeloverrides the configured model for this call.
Questions
Question ids match ^[A-Za-z0-9_.-]{1,64}$. Each question has a type, instructions, and (for choice and score) criteria. Unknown fields are rejected.
{
"card_logged": {
"type": "noul",
"instructions": "Does any changed line write a card number or CVV to a log?"
},
"layer": {
"type": "choice",
"instructions": "Which layer does this change mainly touch?",
"criteria": {"frontend": "UI code", "backend": "server code", "database": "schema or queries"}
},
"risk": {
"type": "score",
"instructions": "How risky is deploying this change?",
"criteria": ["No risk", "Low risk", "Moderate risk", "High risk"]
}
}noul:criteriais optional; if given it must be{"true": "...", "false": "..."}.choice:criteriais an object of 2 to 255 options (name to description; a description may benull).score:criteriais an array of at least 2 level descriptions, lowest first.instructionsis a string in the advertised tool schema. At runtime a JSON object or array is also accepted (Jev takes structured instructions) and sent as given.
Ready-to-use inputs are in examples/.
Output
{
"session": "/home/u/.jev-answers/sessions/20260930-164512-payment-review-7f3a",
"status": "ok",
"response": {
"model": "jev-1.13.0",
"answers": {
"card_logged": {"type": "noul", "noul": 0.03}
},
"usage": {"input_tokens": 476, "output_tokens": 12}
}
}response is the provider's body, unchanged. On failure:
{
"session": "...",
"status": "error",
"error": {"stage": "build", "type": "context_too_large", "message": "...", "details": {}}
}stage is one of config, session, collect, build, send. config and session errors happen before a session folder exists or is usable, so session may be null.
Error types: config_error, session_error, internal_error, invalid_input, invalid_question, file_not_found, file_unreadable, binary_file, secret_file, file_too_large, too_many_files, missing_artifact, context_too_large, auth_error, payment_required, invalid_request, rate_limited, overloaded, provider_error, timeout, network_error, invalid_response, cancelled.
Provider error bodies are kept in error.json under details.body: JSON bodies up to 8 KB as they are, larger ones cut to the first 8 KB as text with details.body_truncated: true. The API key and any Bearer ... token are replaced with [redacted] in every recorded or returned error.
Over MCP, errors come back as a normal tool result with isError: true.
Reviewing a diff
The tool does not run git. Write the diff to a file and pass it:
mkdir -p /tmp/jev
git diff main...HEAD > /tmp/jev/change.diffgit diff leaves out untracked files. Add them by diffing each one against /dev/null, which does not touch your index:
{
git diff main...HEAD
git ls-files --others --exclude-standard -z | xargs -0 -I{} git diff --no-index /dev/null {}
} > /tmp/jev/change.diffThen pass {"path": "/tmp/jev/change.diff", "label": "git diff of the change under review"} together with the files that give the diff its context.
Writing good questions
One specific, checkable fact per question. Prefer "Does any changed line log a card number?" over "Is there a security issue?". Generic "is there a bug?" questions are unreliable.
Ask about written rules and requirements, and put those rules in
context.No arithmetic, counting or date math. Work it out yourself first, then ask about the result.
Keep the state small: pass only the relevant files. Irrelevant context lowers accuracy.
Many questions per call is fine and cheap; they are all answered in one pass.
CLI
jev-answers serve start the MCP server on stdio (also "mcp"; no args + piped stdin does the same)
jev-answers setup [options] interactive setup (see Install for the non-interactive flags)
jev-answers ask [file|-] run a tool-input JSON file or stdin, print the result; exit 0 ok / 1 error
jev-answers resend <session> send an earlier session's request again, in a new session
jev-answers list [--limit N] newest first (default 20)
jev-answers show <session> [--path] print response.json (or error.json), or the folder path
jev-answers prune --older-than 30d [--yes]
jev-answers skill <action> install | uninstall | status | show the optional agent skill
jev-answers doctor [--live] effective config with sources, folder check; --live sends one tiny question
jev-answers config config file path and effective config (key masked)<session> is an id, a unique part of an id, a folder path, or latest.
Limits
Jev accepts about 64k tokens per request in total and about 32k for the state plus the single longest question. This tool estimates tokens conservatively (ASCII characters / 3.5, plus one token for every non-ASCII character, since Persian, CJK and similar text tokenizes much worse) and, by default, stops at 28k and 56k so oversized requests fail locally with
context_too_large(listing the five largest files) instead of being sent and billed.Per file: 1 MiB by default. Per call: 200 files by default.
Retries: network errors, timeouts and HTTP 408, 429, 500, 502, 503, 504, 524 and 529 are retried with exponential backoff (1s, 2s, 4s, capped at 30s), honouring
Retry-Afteras a minimum. If the server asks for more than 60 seconds, retrying stops and the call fails (rate_limitedoroverloaded, withdetails.retry_after_seconds). 400, 401, 402, 403, 404, 413 and 422 are never retried, and neither are redirects (they are not followed; setbase_urlto the final URL) or invalid URLs.Bounds:
timeout_ms1000 to 2147483647,max_retries0 to 10; other numeric settings must be positive (retention_daysmay be 0).
Privacy and security
The contents of the files you pass, the
contextand the questions are sent to the configured provider (TypeSafe or OpenRouter). Nothing else is sent. The tool makes no other network calls.Secret-looking files are blocked:
.envand.env.*(but not.env.example,.sample,.template,.dist),*.pem,*.key,*.p12,*.pfx,*.jks,*.keystore,*.kdbx, SSH private keys (id_rsa,id_dsa,id_ecdsa,id_ed25519),.npmrc,.pypirc,.netrc,.git-credentials,.envrc,*.tfvars,terraform.tfstate(and.backup),*.ppk,.htpasswd,.docker/config.json,.aws/credentials, and SSH private keys with any suffix (id_rsa_work, but not*.pub). Any.env.*ending in.example,.sample,.templateor.distis allowed. Glob and directory expansion skips secret files; naming one explicitly is an error. Setallow_secret_filesto override. This is a name-based safety net, not a scanner: secrets inside ordinary files are not detected.The API key lives in the config file with mode 0600 (the directory is 0700) or in an environment variable. It is never written to a session folder and is masked in all output.
Session folders are stored locally and contain full copies of what was sent, so they may hold sensitive code. They live under
~/.jev-answers(mode 0700). Setretention_daysto delete old sessions automatically, or runjev-answers prune.base_urlmust use https, because the key is sent in theAuthorizationheader. Plain http is accepted only for loopback hosts (localhost,127.0.0.0/8,::1). Redirects are not followed, so the key cannot be forwarded to another host.Userinfo and query strings in
base_urlare masked inmeta.jsonand inconfig/doctoroutput. Keys containing whitespace or non-ASCII characters are rejected without being echoed.Session files are written with mode 0600 (folders 0700).
Agent skill (optional)
An MCP tool description teaches an agent how to call jev_ask. Some clients defer tool descriptions and show only tool names plus the server's short instructions, and none of them say when to reach for Jev in your workflow. The optional skill adds that: when to use it, how to gather rules and write the diff, how to phrase questions and how to read the probabilities. It is an Agent Skills folder that only loads when relevant.
target | path | read by |
|
| Claude Code, OpenCode |
|
| Codex, OpenCode, other Agent Skills clients |
With --project the same folders are used under the current directory (./.claude/skills/..., ./.agents/skills/...), so a team can commit the skill.
jev-answers skill install [--target claude,agents] [--project] [--force]
jev-answers skill status # not installed / installed vX (current|outdated) / foreign
jev-answers skill uninstall [--target claude,agents] [--project]
jev-answers skill show # print the rendered SKILL.mdsetup offers the skill for each client it detects; non-interactively use setup --yes --skill claude,agents. Without --target, install picks claude if claude is on your PATH and agents if codex or opencode is, or both if none is found. The skill is always copied, never symlinked. A SKILL.md that is not ours (no source: jev-answers in its frontmatter) is never overwritten without --force, and uninstall only removes our own file. OpenCode reads both locations, so installing both shows it the same skill twice, which is harmless. Re-run skill install after upgrading to refresh it; skill status and doctor tell you when it is outdated.
Without the skill, put this in CLAUDE.md / AGENTS.md:
jev-answers skill show > /tmp/jev-skill.md # then paste the body into your instructions fileTroubleshooting
jev-answers doctorshows the effective config and where each value comes from.doctor --livesends one tiny question to verify the key and endpoint.config_error: No API key configured: runjev-answers setup, or setJEV_ANSWERS_API_KEY.config_errormentioning a placeholder: your client passed a literal${...}as the key. Put the key in the config file instead.context_too_large: the error lists the largest files. Drop or narrow them, or pass a smaller diff.secret_fileorbinary_filefor a file you named: it is blocked on purpose. Copy the relevant part to a plain file, or setallow_secret_files.auth_error(401/403): wrong or revoked key. On OpenRouter use an inference key, not a management key.invalid_input"Nothing to send": every file you listed was skipped (secret, binary, symlink, ...) and there was nocontext. Seemanifest.jsonfor the reasons.Server prints nothing in the client: run
JEV_ANSWERS_DEBUG=1 jev-answers serveand watch stderr. stdout is reserved for JSON-RPC.Look inside the session folder (
jev-answers show latest --path):request.jsonis exactly what was sent, anderror.jsonhas the provider's error body.
Development
npm test # node --test "test/**/*.test.js"; no network access neededTests use a local fake provider and temporary directories; they never touch ~/.jev-answers or your real config. The code is plain ESM with no dependencies. Layout:
bin/jev-answers.js CLI entry
src/stages/ collect, build, send (independent, each reads the session folder)
src/providers/ typesafe.js, openrouter.js
src/pipeline.js ask() runs the three stages and never throws
src/mcp/ stdio JSON-RPC server and the tool definition
src/cli/ setup, ask, resend, list, show, prune, doctor, configLicense
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
A paid remote MCP for Skybridge, built to return verdicts, receipts, usage logs, and audit-ready JSO
A paid remote MCP for Equibles, built to return verdicts, receipts, usage logs, and audit-ready JSON
A paid remote MCP for Unity-MCP, built to return verdicts, receipts, usage logs, and audit-ready JSO
A paid remote MCP for ppt-master, built to return verdicts, receipts, usage logs, and audit-ready JS
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables MCP clients to call TypeSafe's JEV classifier and receive structured, typed judgments with probabilities for binary, choice, and scoring questions.17MIT
- AlicenseNot gradedqualityDmaintenanceEnables MCP hosts to query Jev's typed decision model—yes/no, choice, and score—with calibrated probabilities, while defaulting to an offline mock and disclosing all egress unless explicitly enabled.97Apache 2.0
- AlicenseNot gradedqualityBmaintenanceAn MCP server that exposes eleven typed decision tools—check, choose, score, judge, route, triage, guard, grep, rank, compact, and ask—so agents can make fast, branchable yes/no, option-pick, score, and filtering decisions on text via TypeSafe's Jev model.134 npm3MIT
- AlicenseNot gradedqualityBmaintenanceEnables MCP clients to get machine-readable yes/no, choice, and score decisions from TypeSafe Jev, bridging fast classification to Cursor and other clients.MIT