Skip to main content
Glama

mcp_jev

Local MCP server that runs TypeSafe Jev (System One) packs — typed Choice / Noul / Score judgments, not chat. When no pack fits, run_questions is the typed custom path (still System One, still not an essay).

Anyone runs it on their own PC with their own TypeSafe API key. This repo does not host Jev, proxy your key, or invent a free-form ask_jev tool.

Configure the TypeSafe key once during MCP install (~/.mcp_jev/.env). Any agent that attaches this MCP reuses it. Do not paste the key into host mcp.json / TOML.

Docs (source of truth): this repo — https://github.com/pedroknigge/mcp_jev · TypeSafe API: docs.typesafe.ai · llms.txt

Skill: skills/mcp_jev/SKILL.md · Custom judgments: docs/CUSTOM_JUDGMENTS.md · Blind dogfood: docs/DOGFOOD.md · Product backlog: docs/BACKLOG.md · Host deep dive: docs/INSTALL_AGENTS.md · Releases: docs/RELEASES.md

Why mcp_jev

mcp_jev is the judgment layer for agents and harnesses. Jev is fast at typed decisions (one Choice, a few Nouls, a Score) over a short named state. It is not a chat model and not an executor.

Use it when the host already has structured state and needs a closed-catalog call:

Layer

Owns

Harness / agent

Observation, tools, typed strings, merges, comments, stop rules

mcp_jev

Versioned packs or typed custom questions → systemOne → Choice / Noul / Score

Host config

Keyless command = ~/.mcp_jev/bin/mcp_jev

Closed tools only: list_packs / describe_pack / run_pack / run_questions / ping. Key-once in ~/.mcp_jev. Patterns here follow common ecosystem loops (computer-use, review pipelines, model routing) reimplemented as packs — no copied code, no third-party trademarks. Packs are shortcuts: if one fits, run_pack. If none fits, build closed state + typed Choice / Noul / Score and call run_questions.

Jev (System One)

Chat LLM

Input

State + closed questions

Prompt / conversation

Output

choice / noul / score + probabilities

Prose you must parse

Control

Your code composes answers

The model narrates a plan

This MCP

Runs a pack or typed run_questions

Out of scope

JavaScript SDK (what this server calls):

import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient(); // reads TYPESAFE_API_KEY
await client.systemOne({
  state: { /* pack state */ },
  questions: {
    intent: choice("…", { faq: "…", action: "…" }),
    jailbreak: noul("…"),
    urgency: score("…", ["routine", "soon", "emergency"]),
  },
  model: "jev-latest",
});

Python exists (typesafe-sdk, client.system_one) if you are writing app code. This server is TypeScript / Node 20+.

Related MCP server: Jev MCP

Install (happy path)

Prerequisites: Node.js 20+, git, a TypeSafe key from console.typesafe.ai.

# macOS / Linux — checkout ~/mcp_jev; key + wrapper in ~/.mcp_jev (override: MCP_JEV_HOME)
git clone https://github.com/pedroknigge/mcp_jev.git ~/mcp_jev
~/mcp_jev/scripts/install.sh
# Windows
git clone https://github.com/pedroknigge/mcp_jev.git $HOME\mcp_jev
$HOME\mcp_jev\scripts\install.ps1

Already cloned? Run ./scripts/install.sh from that checkout. MCP_JEV_HOME overrides the config dir (~/.mcp_jev). Optional MCP_JEV_CHECKOUT overrides the git checkout.

The script: clones or pulls → npm install && npm run build → writes ~/.mcp_jev/bin/mcp_jev → stores TYPESAFE_API_KEY once in ~/.mcp_jev/.env (chmod 600) → prints keyless snippets for Cursor, Claude Desktop, Claude Code, Codex, Grok, and Antigravity.

Non-interactive and no key → writes ~/.mcp_jev/NOT_READY, prints a loud next step, exits non-zero. mcp_jev doctor fails until mcp_jev config set-key. Do not treat a missing key as a successful install.

Optional host write: MCP_JEV_WRITE_HOSTS=all ./scripts/install.sh (or cursor,claude_desktop,claude_code,codex,grok,antigravity). Merge is additive; existing servers stay.

Paste this keyless block (the script prints your real wrapper path):

{
  "mcpServers": {
    "mcp_jev": {
      "command": "/Users/YOU/.mcp_jev/bin/mcp_jev"
    }
  }
}

Then mcp_jev doctor → restart the host → pinglist_packs.

Non-interactive key: TYPESAFE_API_KEY=… ./scripts/install.sh
Later: node ~/mcp_jev/dist/index.js config set-key

Alternatives

Style

When

Install script (prefer this)

Humans and agents. Key once, keyless host config.

Git clone + manual build

npm install && npm run build && npm test in REPO_PATH. Then node dist/index.js config set-key.

npx -y github:pedroknigge/mcp_jev

No clone. Slow first start. Still run config set-key so hosts stay keyless.

npm registry (npx mcp_jev)

Not used. This project is not published to npm. Install from GitHub; update with scripts/update.sh. See docs/RELEASES.md.

npm test mocks TypeSafe and must pass without a live key.

First-run

mcp_jev doctor          # checkout, dist, wrapper, api_key_set (boolean), host registration
# or: node ~/mcp_jev/dist/index.js doctor --json
mcp_jev smoke           # stdio JSON-RPC: initialize, tools/list, ping, list_packs
~/mcp_jev/scripts/verify-mcp.sh   # same smoke as a script
npm run smoke:packs               # ping → list_packs → describe+run every pack (mocked TypeSafe)

On the host, after restart:

  1. pingok, packs ≥ 12, api_key_set boolean. Never invent run_pack / run_questions answers if the key is missing.

  2. list_packs — pick an id.

  3. If a pack fits: describe_pack then run_pack. If none fits: run_questions (closed state + typed Choice / Noul / Score).

CLI: mcp_jev doctor · mcp_jev smoke · mcp_jev scan <path> · mcp_jev hosts print · mcp_jev hosts write all · mcp_jev config set-key · mcp_jev config status.

Verify

npm test                         # unit tests; mocked TypeSafe; no live key
./scripts/verify-mcp.sh          # stdio JSON-RPC: initialize, tools/list, ping, list_packs
npm run smoke:packs              # ping → list_packs → describe_pack + run_pack(example_state) for every pack
npm run smoke:packs -- --live    # real TypeSafe from TYPESAFE_API_KEY or ~/.mcp_jev/.env

Default smoke:packs injects the same mocked systemOne pattern as npm test (no network). It prints a table (pack, ok, ms, error) and exits non-zero if any pack fails. --live is skipped in CI unless TYPESAFE_API_KEY is set and SMOKE_LIVE=1.

Recipes

run_questions (first-class; no exact pack)

Packs are shortcuts. Same systemOne path as run_pack. Not “write me a review”. After a pattern repeats 2–3 times, upstream a named pack.

Blind dogfood: invent typed questions before opening the pack list; use a pack only if it matches exactly — docs/DOGFOOD.md. Model-lane cascades with custom option ids → model route via run_questions (do not stretch model_router).

Example (public-API / changelog break — no pack): state { path, change_summary, symbols:[{id,kind,note}] } + Noul is_breaking_for_callers + Score doc_debt + Choice hottest_symbol over symbol ids plus none. Full recipe: docs/CUSTOM_JUDGMENTS.md.

i18n via run_questions (equal to run_pack i18n_copy)

Closed candidates[], same Login / Submit / Error loading demo as the pack. Extra Noul needs_locale_split means i18n_copy is not an exact match — stay on run_questions. Runnable: npm run smoke:blind-i18n (mocked) or --live.

{
  "state": {
    "path": "src/components/LoginForm.tsx",
    "language": "tsx",
    "framework_i18n": "next-intl",
    "uses_i18n_api": false,
    "locale_files_present": true,
    "candidates": [
      { "id": "login_heading", "text": "Login", "kind": "jsx_text", "line": 12 },
      { "id": "submit_btn", "text": "Submit", "kind": "jsx_attr", "line": 40 },
      { "id": "load_error", "text": "Error loading", "kind": "toast", "line": 55 }
    ]
  },
  "questions": [
    {
      "id": "has_user_facing_hardcoded_copy",
      "type": "noul",
      "instructions": "Given `path`, `candidates`, and `uses_i18n_api`, does this file contain user-facing hardcoded copy that is not already going through an i18n API?",
      "criteria": {
        "true": "At least one candidate is user-visible copy that would ship in one language.",
        "false": "Candidates are identifiers, logs, tests, or already passed through t() / useTranslations."
      }
    },
    {
      "id": "should_migrate_to_i18n",
      "type": "noul",
      "instructions": "Should the caller extract the user-facing strings in `candidates` into the project's i18n layer before a multi-locale ship?",
      "criteria": {
        "true": "Hardcoded user-facing copy should move to locale files / t() before shipping more locales.",
        "false": "No migration needed: already i18n, copy is dev-only, or a multi-locale ship is not indicated."
      }
    },
    {
      "id": "i18n_debt",
      "type": "score",
      "instructions": "How much i18n debt does this file add to a multi-locale ship, given `candidates` and `uses_i18n_api`?",
      "criteria": [
        "Clean: no user-facing hardcoded copy.",
        "Local leftover: a few strings, easy extract.",
        "Cross-cutting: many strings or mixed buckets; needs a focused pass.",
        "Blocking for a multi-locale ship: user-facing copy would ship untranslated."
      ]
    },
    {
      "id": "hottest_candidate",
      "type": "choice",
      "instructions": "Which `candidates[].id` is the hottest string to extract first? Options are only those ids plus `none`.",
      "criteria": {
        "login_heading": "kind=jsx_text; text=Login; line=12",
        "submit_btn": "kind=jsx_attr; text=Submit; line=40",
        "load_error": "kind=toast; text=Error loading; line=55",
        "none": "No single candidate stands out to extract first."
      }
    },
    {
      "id": "needs_locale_split",
      "type": "noul",
      "instructions": "Should labels and toasts in `candidates` land in different locale namespaces (UI strings vs errors) rather than one dump?",
      "criteria": {
        "true": "UI labels and error/toast copy should split across locale files or namespaces.",
        "false": "One locale namespace is enough, or there is no user-facing copy."
      }
    }
  ]
}

Blind-test protocol

  1. Invent typed Choice / Noul / Score questions before opening list_packs.

  2. Use a pack only if it matches exactly.

  3. Otherwise run_questions. Full protocol: docs/DOGFOOD.md.

computer_use_step (harness)

Code owns OCR / accessibility / DOM, clicks, and the writer LLM for free text. Jev only picks the next operation and a target from your closed catalogs.

  1. Observe in the harness. Build items[] (and optional offscreen_items[]) with stable ids. Cap the catalog before 255 (Choice cap includes none). Prefer source: "dom" when ids are DOM-closed; ax / ocr when that is what you observed. Short observation_summary. No screenshots, pixels, or image blobs in state (rejected as invalid_state).

  2. run_pack computer_use_step with goal, app_or_url, that observation, recent history, and flags.

  3. One systemOne call fans out operation plus a separate target Choice per op (click_target, type_target, offscreen_target) plus goal_achieved, observation_stale, step_confidence. Each target question assumes its operation.

  4. Prefer additive guidance: target_for, ignore_targets, effective_targets, writer_owns_typed_string, harness_hints. Raw answers stay intact. Act only on guidance.effective_targets / guidance.target_for[operation].

  5. For type_text / type_email, a writer LLM (or stored value) supplies the string. max_steps / max_candidates stay in the harness.

  6. Example thresholds (tune on your traces): stop if goal_achieved.noul ≥ 0.8 or operation is done; re-observe if observation_stale.noul ≥ 0.65 or step_confidence.score < 1.5.

Example state:

{
  "goal": "Sign in with the saved work account",
  "app_or_url": "https://app.example.com/login",
  "observation_summary": "Login form: email focused and empty, password empty, Sign in button, Forgot password link.",
  "focused_field": "email",
  "items": [
    { "id": "email", "role": "textfield", "label": "Work email", "region": "form", "source": "ax" },
    { "id": "password", "role": "textfield", "label": "Password", "region": "form", "source": "ax" },
    { "id": "sign_in", "role": "button", "label": "Sign in", "region": "form", "source": "ax" }
  ],
  "history": [{ "action": "wait", "result": "form_visible" }],
  "flags": { "loading": false, "login_required": true }
}

model_router (per-turn lane)

Call at turn start, before tools. Map route.choice in code (unit-test the mapper; no TypeSafe key). Do not invent a sixth lane.

Closed lanes: fast_local | strong_reasoner | tools_heavy | ask_user | skip.

Lane

Meaning

fast_local

Cheap/local or no model: lookup, format, one obvious tool

strong_reasoner

Ambiguous design, hard failure, plan not yet mechanical

tools_heavy

Long tool / browser / shell loop

ask_user

Missing preference, secret, or confirmation

skip

Already done, blocked, or out of scope

Example thresholds (caller-owned): route.confidence < 0.45ask_user; unsafe_or_irreversible.noul ≥ 0.70 → refuse or confirm; simple_lookup.noul ≥ 0.75 and difficulty.score < 1.5 → force fast_local.

Recipes table

Need

Pack

Typed Choice / Noul / Score with no exact pack (incl. i18n + extra heads)

run_questions (not a pack)

Next GUI step from a closed element catalog

computer_use_step

Model cascade / per-turn compute lane

model_router

Skill select from a closed list

skill_router

Command risk signals

command_risk

Generic diff review

review_diff

Repo tree / architecture / "try Jev on these files"

mcp_jev scancode_audit (Pass 1; not pr_audit)

Domain example: money / labor-hours / migration PR-shaped merge risk

pr_audit

Item / SKU locale from a caller-supplied closed country list

locale_country

Claimed behavior vs named tests / CI

verify_gap

One module’s imports/exports vs layer

boundary_check

Hardcoded UI copy vs i18n (t() / locale files)

i18n_copy if exact match; else run_questions (i18n recipe above)

Code-owned policy: keep thresholds in your functions (see src/policy-examples.ts; unit-test them without a TypeSafe key). Jev returns signals; your gate decides. Allowlist/sandbox still required for shell.

verify_gap: one claim vs named evidence → verifyGapCodeGate (ship | add_proof | block). boundary_check: one module’s imports/exports → fix (keep | extract | move_layer | unclear).

review_diff (staged review)

Nouls correctness / security / reliability / compat / test_gap → Choice hotspot_file from the closed files[] catalog → Score severity. Orchestration (comment, block, open a file) stays in the caller.

{
  "intent": "Fail closed on reserved catalog ids",
  "diff_summary": "Adds reserved-id checks and a unit test. No auth change.",
  "files": ["src/packs/catalog-choice.ts", "test/computer-use.test.ts"]
}

Example thresholds: request review if any Noul ≥ 0.65; block if security.noul ≥ 0.75 or severity.score ≥ 2.5.

pr_audit is a domain example pack (money / labor-hours / migration merge risk, common in ops/fintech) — not the universal PR pack. Keep the id. PR-shaped state only (title / body / files / diff_summary). General users should start with review_diff (diff) or code_audit (tree). Do not use pr_audit for a repo-tree scan. Never put experiment narrative in title/body. Large path-only batches (~40 files) inflate needs_review/block; path tokens (budget, migration, finance) move Nouls without reading bodies.

code_audit (full-repo / per-file scan)

Millisecond-tier structured engineering audit (layering / blast-radius / verification style checks). Expect ~network RTT per file; parallelize N workers. This is not a multi-second LLM review. Jev must not receive the monorepo as prose.

First-class harness: mcp_jev scan <path> (or node dist/cli.js scan). Do not dump a tree into pr_audit.

mcp_jev scan . --dry-run                 # files + signals; no TypeSafe
mcp_jev scan .                           # Pass 1, concurrency 8
mcp_jev scan . --concurrency 16 --pass2 5

Walks the tree (respects .gitignore; skips binaries, images, lockfiles, node_modules, .git, generated dirs), builds compact signals, and calls code_audit through the same run_pack / systemOne path. JSONL to stdout (or --jsonl PATH); summary on stderr (top-K severity, primary_concern histogram, hottest paths, path-token-only flag count). Progress on stderr: files done/total, rate files/min, ETA. Missing API key → clear error (except --dry-run).

Pass 1 (default, all files): harness lists files → filter screenshots/binaries/generated vendor dirs → compact signals only → parallel run_pack code_audit → aggregate top problem_severity / most frequent Nouls.

Pass 2 (top-N only): resend the hottest files with a short excerpt (hard max 1200 chars; oversized → invalid_state) for confirmation. --pass2 N on the CLI.

6000 files / ~2 min class: keep Pass 1 signals-only. Concurrency default 8; 16–32 is typical for multi-k repos (MCP_JEV_SCAN_CONCURRENCY or --concurrency). --max-files N samples. --resume continues from .mcp_jev-scan-checkpoint.json (written every 50 files). Recipe: parallel Pass 1 → read top severity + path-token FP note → Pass 2 excerpts on top-K only.

mcp_jev scan . --concurrency 16 --summary-only --jsonl scan.jsonl
mcp_jev scan . --concurrency 16 --pass2 20 --summary-only
mcp_jev scan . --resume --summary-only --jsonl scan.jsonl   # after interrupt

Example gate (src/policy-examples.ts gateCodeAudit): ok | glance | deep_review. Unit-test the gate without a TypeSafe key.

Pass 1 state (no body):

{
  "path": "src/billing/invoice-total.ts",
  "language": "ts",
  "role_hint": "domain",
  "signals": {
    "loc": 12,
    "import_count": 1,
    "top_imports": ["money"],
    "has_tests_nearby": false,
    "touches_money": true,
    "is_generated": false,
    "complexity_heuristic": 2
  },
  "repo_context": "Billing module: invoice line totals."
}

Optional Mode B: one call with files[] (paths only) + short batch_notes — Choice hotspot_file from that closed catalog, no bodies. If path is also set, single-file Mode A wins.

i18n_copy (hardcoded UI copy)

Shortcut pack when invented heads match exactly (the three Nouls + i18n_debt + hottest_candidate + primary_bucket). Extra head such as needs_locale_splitrun_questions (recipe above, equal JSON). Per-file audit of hardcoded strings that should live in an i18n layer. The harness extracts a closed candidates[] catalog (max ~20). Jev does not rewrite JSX or locale JSON.

Nouls has_user_facing_hardcoded_copy / should_migrate_to_i18n / already_partially_internationalized → Score i18n_debt (0 clean → 3 blocking for a multi-locale ship) → Choice hottest_candidate from candidates[].id plus none → Choice primary_bucket (ui_copy | error_message | marketing | dev_only | mixed | none).

{
  "path": "src/components/LoginForm.tsx",
  "language": "tsx",
  "framework_i18n": "next-intl",
  "uses_i18n_api": false,
  "locale_files_present": true,
  "candidates": [
    { "id": "login_heading", "text": "Login", "kind": "jsx_text", "line": 12 },
    { "id": "submit_btn", "text": "Submit", "kind": "jsx_attr", "line": 40 },
    { "id": "load_error", "text": "Error loading", "kind": "toast", "line": 55 }
  ]
}

Example gate (src/policy-examples.ts gateI18nCopy): ok | glance | block. Unit-test the gate without a TypeSafe key.

Update

Update from the GitHub checkout, not npm:

~/mcp_jev/scripts/update.sh          # git pull + npm install + build; keeps ~/.mcp_jev/.env
# Windows: ~\mcp_jev\scripts\update.ps1

Do not npm update -g mcp_jev or npx mcp_jev@latest. Public versions are GitHub Releases (v0.0.9 onward). Scheme: docs/RELEASES.md.

Restart the MCP host. update.sh refreshes the skill once to ~/.agents/skills/mcp_jev. Hosts that do not read that path: re-add once (do not also copy — nests mcp_jev/mcp_jev):

npx skills add pedroknigge/mcp_jev --skill mcp_jev

Skill stays in sync

The agent skill lives in-repo at skills/mcp_jev/SKILL.md. Frontmatter description always starts with VERSION — (the package.json version + em dash). npx tsx scripts/sync-skill-catalog.ts / npm test fail if it drifts. This is the template for Pedro skills.

scripts/update.sh pulls the checkout and refreshes the skill once to ~/.agents/skills/mcp_jev (replaces that folder; never nests). Hosts that do not read that path: re-add once with npx skills add pedroknigge/mcp_jev --skill mcp_jev. Do not also copy.

Exact pack ids / question ids / state fields: skills/mcp_jev/references/pack-catalog.md (generated from src/packs/). npm test fails if a new pack or question id is missing from the skill or that catalog.

Say this to your agent

Install and configure mcp_jev from https://github.com/pedroknigge/mcp_jev using the install script and skill. Then run doctor, ping, and list_packs.

Or: run scripts/install.sh (refreshes the skill once to ~/.agents/skills/mcp_jev), paste the printed snippets, restart, doctorpinglist_packs. Do not also npx skills add in the same pass.

Install for agents & IDEs

Easiest path: install script → one keyless command pointing at ~/.mcp_jev/bin/mcp_jevmcp_jev doctor → restart → ping. Full stanzas in docs/INSTALL_AGENTS.md.

The server reads TYPESAFE_API_KEY from ~/.mcp_jev/.env (or $MCP_JEV_HOME/.env). Process env is a fallback only when the store is empty. Host configs must stay keyless.

Generic JSON (most hosts):

{
  "mcpServers": {
    "mcp_jev": {
      "command": "/absolute/path/to/.mcp_jev/bin/mcp_jev"
    }
  }
}

Windows wrapper: %USERPROFILE%\.mcp_jev\bin\mcp_jev.cmd.

Print or merge snippets: mcp_jev hosts print · mcp_jev hosts write all.

Cursor

Project: .cursor/mcp.json · User: ~/.cursor/mcp.json (project wins on name clash).

Skill: install.sh refreshes ~/.agents/skills/mcp_jev once. If you skipped the script, pick one: npx skills add pedroknigge/mcp_jev --skill mcp_jev or rm -rf ~/.agents/skills/mcp_jev && cp -R skills/mcp_jev ~/.agents/skills/mcp_jev. Never both.

Claude Desktop

Settings → Developer → Edit Config, then fully quit.

OS

File

macOS

~/Library/Application Support/Claude/claude_desktop_config.json

Linux

~/.config/Claude/claude_desktop_config.json

Windows

%APPDATA%\Claude\claude_desktop_config.json

Same keyless mcpServers JSON as Cursor.

Claude Code

claude mcp add --scope user --transport stdio mcp_jev -- /Users/YOU/.mcp_jev/bin/mcp_jev

Or merge ~/.claude.json with the generic JSON. Skill: copy to .claude/skills/mcp_jev.

Codex

TOML, not JSON. ~/.codex/config.toml or .codex/config.toml:

[mcp_servers.mcp_jev]
command = "/Users/YOU/.mcp_jev/bin/mcp_jev"

Or codex mcp add mcp_jev -- /Users/YOU/.mcp_jev/bin/mcp_jev.

Grok

~/.grok/config.toml / grok mcp add mcp_jev -- ~/.mcp_jev/bin/mcp_jev. Same TOML table [mcp_servers.mcp_jev].

Antigravity

~/.gemini/config/mcp_config.json or .agents/mcp_config.json — generic JSON, command = wrapper.

Other JSON / TOML hosts

Same wrapper command. Some editors use context_servers instead of mcpServers — see docs/INSTALL_AGENTS.md.

Agent instructions

You have mcp_jev (or you must install it from https://github.com/pedroknigge/mcp_jev). Jev is not chat. No ask_jev.

If the MCP tools are missing: tell the user to run scripts/install.sh (or install.ps1) from that repo, paste the printed snippets, set the key once (config set-key / install prompt), run mcp_jev doctor, restart the host.

Always: list_packs. Packs are shortcuts: if one fits, describe_packrun_pack. If no pack fits, do not stop: build closed state + typed Choice / Noul / Score and call run_questions. Side effects stay in your code. Never put TYPESAFE_API_KEY in chat. If ping.api_key_set is false, run mcp_jev config set-key — do not embed the key in every host config.

Tools (closed catalog)

Tool

Args

What it does

list_packs

none

id, version, title, summary, when_to_use

describe_pack

pack_id

JSON Schema, questions, example_state, suggested_workflow, notes

run_pack

pack_id, state

Validates state, calls TypeSafe systemOne, returns typed answers + usage. No side effects.

run_questions

state, questions, optional model

Fail-closed typed Choice / Noul / Score when no pack fits. Same systemOne path as run_pack. No side effects. Not chat.

ping

none

Versions, pack count, api_key_set, api_key_source (env | user_store | none). Never echoes the key

There is no free-form ask tool. list_packs / describe_pack / ping never call TypeSafe. Only run_pack and run_questions do. Teaching for the custom path: docs/CUSTOM_JUDGMENTS.md.

Packs

id

What Jev judges

What you still do

pr_audit

Domain example (ops/fintech): merge_risk (safe_ui | needs_review | block), Nouls money / hours / hours_money_boundary / migration, Score blast_radius

Staged review: risk Nouls → file Choice over files[] → severity. Compute code_gate. Jev does not merge or comment. Prefer review_diff / code_audit for general PR/tree review

review_diff

Nouls correctness / security / reliability / compat / test_gap; Choice hotspot_file from files[]; Score severity

Default generic PR/diff pack. Orchestration stays in the caller

code_audit

Nouls wrong_layer / blast_radius / missing_verification / secret_or_credential_risk / inefficiency / dead_or_premature_abstraction; Scores problem_severity + change_cost; Choice primary_concern

Pass 1: signals-only, ~RTT per file, N workers. Pass 2: short excerpt on top-N. Aggregate + gateCodeAudit in code

skill_router

Noul needs_skill; Choice skill from available_skills[]; Score change_risk

Load the skill in the host. Thresholds in your code

command_risk

Nouls is_destructive / touches_credentials / scope_matches; Score severity

Allowlist/sandbox still required. Signals only

intent_router

Closed intent Choice, jailbreak + policy Nouls, urgency Score

Route / refuse / hand off in code

locale_country

Catalogue item → one id from the caller’s closed countries[] catalog (or unclear)

Pass your own country list. Write the country to your catalogue

computer_use_step

Next GUI operation + speculative targets; Nouls goal_achieved / observation_stale; Score step_confidence; additive guidance

Observe (OCR/AX/DOM), execute the op, writer LLM for typed text, stop rules

model_router

route (fast_local | strong_reasoner | tools_heavy | ask_user | skip); Nouls code/browser/unsafe/lookup; Score difficulty

Map the lane in code. Thresholds stay in the caller

verify_gap

Nouls has_adequate_verification / claim_is_testable / evidence_matches_claim; Score verification_gap (0 none → 3 ship-blocker); Choice next_proof

Compute code_gate (verifyGapCodeGate → ship | add_proof | block). Jev does not write the test

boundary_check

Nouls crosses_layer / leaks_domain_to_ui / leaks_infra_to_domain; Score boundary_risk; Choice fix (keep | extract | move_layer | unclear)

Extract / move / keep in caller code

i18n_copy

Nouls has_user_facing_hardcoded_copy / should_migrate_to_i18n / already_partially_internationalized; Score i18n_debt (0 clean → 3 blocking); Choice hottest_candidate from candidates[].id; Choice primary_bucket

Truncate to ~20 candidates. gateI18nCopyok | glance | block. Do not rewrite locale files here

Packs live in src/packs/ (in-repo). How to add one: CONTRIBUTING.md.

Breaking (locale_country 2.0.0): country Choice options are no longer a hardcoded country list. Callers must pass countries[] (closed catalog of their own ids, e.g. us, de, jp). unclear remains the pack-owned refuse option.

Architecture

flowchart LR
  Agent[Agent] -->|stdio MCP| Server["mcp_jev"]
  Server --> Packs[Pack registry]
  Server -->|run_pack / run_questions| SDK["TypeSafeClient.systemOne"]
  SDK --> API["POST /v1/systemone"]
  API --> Jev["Jev"]
  Jev -->|typed answers| SDK
  SDK --> Server
  Server --> Agent
  Agent -->|gates and side effects| Code[Your code]

Environment

Variable

Required

Default

TYPESAFE_API_KEY

Yes, for run_pack / run_questions

From ~/.mcp_jev/.env after install

TYPESAFE_BASE_URL

No

SDK: https://api.typesafe.ai

JEV_MODEL

No

jev-latest

TYPESAFE_DEFAULT_MODEL

No

Used if JEV_MODEL is unset

MCP_JEV_HOME

No

~/.mcp_jev (key + wrapper)

MCP_JEV_CONFIG

No

Alias for MCP_JEV_HOME

MCP_JEV_CHECKOUT

No

Git checkout (default ~/mcp_jev or the repo you ran the script from)

MCP_JEV_WRITE_HOSTS

No

Install-time host write (all or comma list)

MCP_JEV_SKILL_HOME

No

Dest for the one skill refresh (default ~/.agents/skills/mcp_jev)

MCP_JEV_SCAN_CONCURRENCY

No

Default parallel workers for mcp_jev scan (8; 16–32 typical for multi-k / 6000-files class)

Repo .env is not auto-loaded. The user store ~/.mcp_jev/.env is. The store wins; process env is fallback only.

CLI: mcp_jev doctor · mcp_jev smoke · mcp_jev scan <path> · mcp_jev hosts print · mcp_jev config set-key · mcp_jev config status · mcp_jev config path.

Security

  • Key lives in ~/.mcp_jev/.env (0600). Never in git, chat, or host JSON. Process env is fallback only if the store is empty.

  • ping / config status / doctor never print the key.

  • scripts/update.sh does not overwrite the key file.

  • Run locally. Do not deploy this stdio binary as a public HTTP proxy.

  • Pack state can contain tickets and diffs — keep diffs summarized.

  • MIT licensed. Jev / TypeSafe are products of TypeSafe; this project is an independent open-source client.

Troubleshooting

Symptom

Fix

doctor / NOT_READY

Non-interactive install without a key. Run mcp_jev config set-key, then mcp_jev doctor.

pingapi_key_set: false

Same. Confirm ~/.mcp_jev/.env exists. Restart the host.

run_pack / run_questions / scanmissing_api_key

Same. --dry-run still works. Do not fabricate answers.

run_packauth

Key rejected (HTTP 401). Rotate at the TypeSafe dashboard, then config set-key.

invalid_state

Re-read describe_pack. Starter packs reject extra fields. computer_use_step also rejects screenshots. Custom run_questions state must be a JSON object.

invalid_questions

run_questions failed schema: Choice needs 2–255 closed options; Score ≥2 levels; use instructions (alias prompt ok); no free-form types.

unknown_pack

list_packs. If none fits, run_questions. There is no ask_jev.

Wrong Node

node -v must be 20+. GUI hosts may not see nvm.

stdio pollution

Wrapper and server must not write to stdout.

npx mcp_jev 404

Expected. mcp_jev is not on npm. Clone GitHub and run scripts/install.sh; later scripts/update.sh. See docs/RELEASES.md.

Scripts

./scripts/install.sh     # happy path
./scripts/update.sh
./scripts/verify-mcp.sh  # stdio smoke, no TypeSafe call
npm run smoke:packs      # mocked run_pack for every pack
npm run smoke:blind-i18n # mocked run_questions-shaped i18n (closed candidates)
npm run build            # tsc → dist/
npm start                # node dist/index.js (MCP stdio)
npm test
npm run typecheck
mcp_jev doctor
mcp_jev smoke            # same stdio check as verify-mcp.sh

License

MIT

Available Tools

5 tools
describe_packDescribe a Jev packA

Return a pack's JSON Schema state, Choice/Noul/Score questions, example state, and suggested agent workflow. Always describe before run_pack when the schema is unfamiliar.

ParametersJSON Schema
NameRequiredDescriptionDefault
pack_idYesPack id from list_packs, e.g. pr_audit

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It states that the tool 'returns' information, implying a read-only operation, but does not explicitly say it has no side effects, require authentication, or describe any rate limits. The return content is listed, but deeper behavioral traits are left implied rather than stated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with zero filler. The main purpose and return contents are front-loaded in the first sentence, and the crucial usage rule is placed second. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter tool with no annotations and no output schema, the description does a solid job: it specifies what is returned, gives a usage trigger, and the parameter reference is well defined. It could be more explicit about the exact format or expected output structure, but given the low complexity, this is not a significant gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% – the single parameter pack_id is already clearly documented in the schema as 'Pack id from list_packs, e.g. pr_audit.' The tool description itself adds no additional meaning about the parameter, so the baseline of 3 applies without penalty or bonus.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a precise verb ('Return') and lists specific resources: JSON Schema state, Choice/Noul/Score questions, example state, and suggested workflow. This clearly distinguishes describe_pack from sibling tools like run_pack and list_packs, which execute and enumerate packs respectively.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The second sentence gives an explicit directive: 'Always describe before run_pack when the schema is unfamiliar.' This directly tells the agent when to use this tool versus run_pack, which is the main alternative it would otherwise confuse with.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_packsList Jev packsA

List the closed catalog of TypeSafe Jev packs. Packs are shortcuts: if an id fits, describe_pack + run_pack. If no pack fits, do not stop — use run_questions with closed state + typed Choice/Noul/Score. There is no free-form ask tool.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses the catalog is 'closed' (static, read-only) and implies a safe listing operation. It does not describe the return format or any edge cases, but for a zero-parameter list operation this is a minor gap rather than a serious one.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences front-load the purpose and then provide the complete routing logic. Every clause earns its place; there is no repetition of schema or annotation content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a list tool with no parameters and no output schema, the description explains how it fits into the broader tool flow: how to proceed with a matching pack, how to fall back to run_questions, and that no free-form ask exists. An agent can invoke it correctly with full awareness of next steps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters and the schema is empty, so the baseline is 4. The description adds no parameter details because none exist, and the routing guidance about 'id' refers to other tools, not this one.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'List the closed catalog of TypeSafe Jev packs.' It is clearly differentiated from siblings by framing packs as shortcuts and explicitly pairing them with describe_pack and run_pack, leaving no ambiguity that this tool only lists rather than executes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit decision rule: 'if an id fits, describe_pack + run_pack' and 'If no pack fits, do not stop — use run_questions.' It also warns against a nonexistent free-form tool. This is exemplary when-to-use guidance that leaves nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pingHealth checkA

Health: server version, TypeSafe JS SDK version, pack count, whether TYPESAFE_API_KEY is set. Never echoes the key.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses what the tool returns and explicitly states the key safety behavior: it never echoes the API key. It could additionally state that it makes no modifications, but a health check is reasonably understood as read-only.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single compact sentence that lists the relevant details and a safety warning. Every word earns its place, and the most important facts are front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only health tool with no output schema, this description is fully adequate. It tells the agent what information will be available and the key security constraint, leaving no critical gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, so the description does not need to explain parameter meaning. The baseline of 4 applies since no parameter information is required.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states exactly what the tool reports: server version, SDK version, pack count, and API key presence. It clearly identifies this as a health check, which distinguishes it from the list/describe/run siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The usage is implied by the name and description: call it to check server health and configuration. However, it does not explicitly say when to use it versus the siblings, nor does it describe common scenarios like verifying connectivity or setup.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_packRun a Jev packA

Validate state and call TypeSafe System One (Jev) for that pack only. Returns typed answers (choice/noul/score), probabilities/confidence where the API provides them, and usage. Requires TYPESAFE_API_KEY. Does not run side effects.

ParametersJSON Schema
NameRequiredDescriptionDefault
stateYesState object matching the pack's JSON Schema from describe_pack
pack_idYesPack id from list_packs

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description takes on the full burden and does well: it discloses the API key requirement, states that no side effects are run, and describes the return content including typed answers, probabilities/confidence, and usage. This goes well beyond the schema fields and gives an agent a clear behavioral model.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded: the main action appears first, followed by return details, authentication requirement, and side-effect note. Every sentence adds meaningful information with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter tool with no output schema, the description covers inputs, return values, auth requirements, and side-effect profile, which is strong. It does not describe failure behavior when validation fails, but the essentials are sufficient for correct tool selection and invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already provides 100% description coverage for both parameters, including pack_id sourced from list_packs and state matching describe_pack's schema. The description does not add additional parameter-level meaning, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific action ('Validate state and call TypeSafe System One (Jev) for that pack only') and identifies the resource (a pack). It distinguishes itself from the sibling tools by focusing on executing a single pack rather than listing or describing packs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'for that pack only' implies usage on a single pack, but the description does not explicitly state when to prefer run_pack over list_packs or describe_pack, nor does it give any exclusions or prerequisites beyond the API key. Usage context is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_questionsRun typed custom questionsA

Typed custom path when no pack shortcut fits. Validate caller-built state plus typed Choice / Noul / Score and call the same TypeSafe System One path as run_pack. Not chat and not essay generation. Prefer run_pack when list_packs has an id (e.g. i18n_copy). Fail-closed schema: Choice is a closed option map (max 255; include a refuse key if needed), Noul is yes/no, Score is ≥2 ordered levels. Returns typed answers + usage. Requires TYPESAFE_API_KEY. No side effects.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelNoOptional TypeSafe model override (default JEV_MODEL / jev-latest).
stateYesCaller-built JSON evidence. Closed and small — not a repo dump.
questionsYesTyped questions: { id, type: choice|noul|score, instructions, criteria }. Not a free-form prompt.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden. It discloses key behaviors: 'No side effects', 'Requires TYPESAFE_API_KEY', 'Fail-closed schema', and 'Returns typed answers + usage'. It doesn't detail error handling or rate limits, but the provided information is strong for a read-like tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-structured: key purpose, usage guidance, schema fail-closed details, and constraints are front-loaded. Each clause adds value, though it could be slightly clearer for non-experts.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (typed questions, nested objects) and lack of output schema/annotations, the description is quite complete. It covers prerequisites (API key), side-effect profile, and schema constraints. Missing output details are noted but acceptable due to description's stated return of 'typed answers + usage'.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description goes beyond the schema: it explains the purpose of 'state' (caller-built, closed, small), the structure of 'questions' (typed, closed option map, max 255, include refuse key), and the semantics of Noul and Score. This adds substantial meaning for correct parameter construction.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: to run typed custom questions via a specific path ('TypeSafe System One') when no pack shortcut fits. It distinguishes it from siblings by explicitly mentioning 'run_pack' and noting it is 'Not chat and not essay generation.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance: 'Prefer run_pack when list_packs has an id' and states it is not for chat or essay generation. It also describes the fail-closed schema constraints, which are critical for correct usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.0.9
    • Addedrun_questions
  2. 4 tool updatesv0.1.0
    • First observeddescribe_pack
    • First observedlist_packs
    • First observedping
    • First observedrun_pack

TDQS

A4.4/5.0

Scored across 5 tools

Disambiguation4/5

Each tool has a distinct role: listing packs, describing a pack, running a pack, running custom questions, and health checking. The only potential confusion is between run_pack and run_questions since both invoke the same TypeSafe System One path, but their descriptions clearly separate pack-based from custom typed workflows.

Naming Consistency4/5

Most tools follow a clear verb_noun pattern: list_packs, run_questions, describe_pack, run_pack. The one outlier is the one-word health tool 'ping', which breaks the pattern but is a common and recognizable convention.

Tool Count5/5

Five tools is a well-scoped size for a focused server that handles pack listing, description, execution, custom question runs, and health checks. Each tool has a clear purpose and none feel redundant.

Completeness5/5

The server covers the full intended workflow: discover packs via list_packs, understand via describe_pack, execute via run_pack, handle non-pack cases via run_questions, and verify health via ping. Since the pack catalog is closed and free-form ask is intentionally excluded, there are no significant gaps.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables MCP clients to call TypeSafe's JEV classifier and receive structured, typed judgments with probabilities for binary, choice, and scoring questions.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables frontier coding agents to delegate routine probabilistic judgments to TypeSafe Jev, providing calibrated triage signals for failures, attempts, completion, context ranking, findings, risk, and generic evidence-grounded questions.
    7
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables prototyping, running, and evaluating typed judgment questions against TypeSafe's Jev model, including accuracy, calibration, and threshold analysis.
    3
    1
    MIT