Skip to main content
Glama

jev-mcp

A general-purpose MCP server for System One decision models such as TypeSafe Jev and Cloudflare Clef. It lets MCP clients ask typed questions (yes/no, choice, score) about structured state and get back calibrated probabilities.

MCP client → stdio → MCP tools → JEV Core → JevProvider → TypeSafe API or OpenRouter

See AGENTS.md for architecture and development rules, docs/typesafe-api-notes.md and docs/openrouter-notes.md for the verified API contracts, and CHANGELOG.md for release history.

Requirements

  • Node.js 20.12 or later

  • A TypeSafe API key, or an OpenRouter API key

Related MCP server: jevjam

Setup

npm install
cp .env.example .env   # then set the key for your provider in .env
npm run build

Variable

Required

Default

JEV_PROVIDER

no

typesafe (or openrouter, local)

JEV_PROVIDERS

no

unset: only JEV_PROVIDER. Comma-separated providers clients may select per request (see Several providers)

TYPESAFE_API_KEY

when JEV_PROVIDER=typesafe

—

TYPESAFE_BASE_URL

no

https://api.typesafe.ai

OPENROUTER_API_KEY

when JEV_PROVIDER=openrouter

—

OPENROUTER_BASE_URL

no

https://openrouter.ai/api (API root, without /v1)

JEV_LOCAL_BASE_URL

no

http://127.0.0.1:8097 (server root, without /v1)

JEV_LOCAL_API_KEY

no

unset: no Authorization header

JEV_MODEL

no

jev-latest

JEV_MAX_RETRIES

no

2 (0 to 10; 0 disables retries)

JEV_IMAGE_DIRS

no

unset: image path disabled. Absolute directories, separated by ; on Windows and : elsewhere

JEV_MAX_INPUT_CHARS

no

256000 characters of state plus questions per request; 0 disables

JEV_MAX_CONCURRENCY

no

4 (1 to 16) provider requests at a time in jev.evaluate_batch

JEV_TIMEOUT_MS

no

30000 (1000 to 600000) milliseconds per provider request attempt

JEV_LOG_LEVEL

no

warn (or error, info, debug); see Logging

JEV_HTTP_TOKEN

for npm run start:http

— (at least 32 characters; see Streamable HTTP)

PORT

no

8098, port of the Streamable HTTP server

JEV_HTTP_HOST

no

127.0.0.1; 0.0.0.0 only inside a container (see Docker)

Checks before sending

Requests the server can tell will fail, or will be billed for nothing useful, are stopped before they reach the provider:

Check

Why

Text input over JEV_MAX_INPUT_CHARS

Clef accepted and billed inputs far beyond its documented context (118k tokens). 256,000 characters is about 64k tokens of English; text in Korean and similar scripts uses more tokens per character, so lower the limit if most input is such text

Images to a model that cannot read them

Jev answers images with confident wrong results and bills them as text

Clef rules: question IDs (letters, digits, _ . -), 2 to 255 choice options, at most 64 questions, about 384 KB of images per request

Clef returns 422 or 413 otherwise; the local message names the problem

Image count, format and size limits

See Images

Requests the provider rejects were not billed in testing, so these checks mainly prevent wasted spending on accepted requests and give clearer errors. Details: docs/openrouter-notes.md.

The stdio server loads .env from the package root when present. Variables already set by the MCP client or shell take precedence.

Providers

JEV_PROVIDER selects one provider. It never switches to another provider on its own, and a missing key for the selected provider is a configuration error.

JEV_PROVIDER

Models (JEV_MODEL)

Cost in results

typesafe (default)

jev-latest, jev-preview, jev-1.13.0

not reported

openrouter

cloudflare/clef, cloudflare/clef-flash, typesafe/jev-1.13, jev-latest, openai/gpt-6-luna-decisions (public beta)

usage.costUsd

local

Whatever your local System One server serves, for example clef-flash with llama.cpp

not reported (no per-request cost)

Several providers in one server

JEV_PROVIDERS lets clients choose the provider per request, for example to ask Jev and Clef the same question:

JEV_PROVIDER=typesafe                  # default when a request names none
JEV_PROVIDERS=typesafe,openrouter,local

Every question tool then takes an optional provider, and results report which provider answered. jev.models lists the models of every provider, each tagged with its provider; a provider that cannot be reached (such as a stopped local server) appears under errors instead of failing the list.

  • Each listed provider needs its own key; one provider's key is never used for another, and a missing key is a configuration error.

  • Without JEV_PROVIDERS, only JEV_PROVIDER is used, even if other keys are set.

  • JEV_MODEL applies to the default provider. A request that selects TypeSafe or a local server without a model uses jev-latest; OpenRouter needs an explicit model, such as cloudflare/clef-flash or typesafe/jev-1.13.

  • An unknown provider is rejected before anything is sent.

JEV_PROVIDER=local uses a server on your own machine or network: no data leaves it. Setup with llama.cpp and Clef Flash, and measured results: docs/local-provider.md.

On OpenRouter, Clef needs its full ID (cloudflare/clef-flash, not clef-flash), accepts at most 64 questions per request, and Jev's context is 32k tokens instead of 64k. jev.models lists the decision models OpenRouter exposes. Details: docs/openrouter-notes.md.

openai/gpt-6-luna-decisions is OpenAI's Decisions API, in public beta since 2026-10-06 ("we expect to GA in the coming weeks"), so its behavior may change. It reads images and accepts long inputs, but it can refuse a question on content-policy grounds, which fails the whole request; the server reports that as refused and does not retry. Do not rely on it for production decisions before general availability.

Models differ in how confident they are. In testing Clef reported lower confidence than Jev, and GPT-6 Luna mostly returned probabilities of 0 or 1, so set thresholds per model from labeled examples.

Images

Every question tool (jev.evaluate, jev.noul, jev.choice, jev.score) takes an optional images list, judged together with state. Images are not tied to any use case: inspection photos, site photos, screenshots and documents all go through the same field.

{
  "state": { "line": "B", "note": "Customer return" },
  "instructions": "Does the part in the photo show a visible defect?",
  "images": [
    { "path": "D:/inspections/2026-10-07/part-0412.jpg" },
    { "data": "data:image/png;base64,iVBORw0KGgo..." }
  ]
}

Source

Use

Rule

path

Agents on the same machine (Claude Code, Codex, VS Code)

Absolute path inside a JEV_IMAGE_DIRS directory; disabled when unset

data

Programs that already hold the bytes

Base64 data URL

Before anything is sent, JEV Core checks that there are at most 4 images, that each is PNG, JPEG or WebP (from the bytes, not the name), and that each is at most 4 MiB with 8 MiB in total. Image parts placed inside state are rejected.

For Clef through OpenRouter the practical limit is much lower than Clef documents: requests with more than about 384 KB of images in total fail there (measured, not documented), so they are rejected before sending. Downscale or recompress photos first; a 1024-pixel JPEG is usually well under the limit. GPT-6 Luna accepted a 624 KB photo.

Only image-capable models receive images: today cloudflare/clef, cloudflare/clef-flash and openai/gpt-6-luna-decisions with JEV_PROVIDER=openrouter, and local models the server lists with an image input (for example Clef Flash in llama.cpp with --mmproj, which cannot load WebP). Requests with images to any other model, including Jev, fail before they are sent, because Jev answers images with meaningless probabilities instead of an error. Details: docs/openrouter-notes.md.

JEV_IMAGE_DIRS exists because the tools are called by AI agents: content an agent reads could ask it to send a private file. Only files inside the listed directories (resolved through symbolic links) can be read.

Clients

Verified with Claude Code, Codex CLI and ChatGPT (through OpenAI's Secure MCP Tunnel). Setup for each client, plus VS Code and Claude Desktop: docs/clients.md.

To build another application on jev-mcp (choosing tools, writing questions, providers, errors, cost and decision thresholds), read the integration guide: docs/usage.md. The server also sends a short usage guide to every client in its MCP instructions, so a connected AI knows how to use the tools.

Streamable HTTP

Besides stdio, npm run start:http serves the same tools over Streamable HTTP at http://127.0.0.1:8098/mcp, so several clients on this machine can share one server. It needs JEV_HTTP_TOKEN (at least 32 characters), which every request must send as Authorization: Bearer <token>. It listens on 127.0.0.1 only and rejects requests whose Host or Origin is not a loopback address, which blocks DNS rebinding. It is stateless: no sessions and no event stream. Remote access, TLS and OAuth are not supported. Client setup: docs/clients.md.

Docker

The same HTTP server also runs in Docker, which brings it back by itself after a restart:

docker compose up -d --build   # build and start in the background
docker compose ps              # shows (healthy) once it answers
docker compose logs            # server output
docker compose down            # stop and remove the container

compose.yaml reads .env at run time, so keys and JEV_HTTP_TOKEN never enter the image, and publishes the port on 127.0.0.1:8098 only. Clients connect exactly as to npm run start:http. The container runs as the unprivileged node user with a read-only filesystem and no capabilities, and checks its own health with an authenticated request. It restarts unless you stop it. To have it running after a reboot, enable Start Docker Desktop when you sign in in Docker Desktop's settings.

Inside the container the server listens on 0.0.0.0 (JEV_HTTP_HOST), because Docker forwards the published port from outside the container. The Host, Origin and token checks still apply. Keep the published host port equal to PORT. Paths in .env such as JEV_IMAGE_DIRS refer to the host and are cleared in the container; mount a folder to use image paths (see the comment in compose.yaml).

Inside the container 127.0.0.1 is the container itself, so compose.yaml sets JEV_LOCAL_BASE_URL to http://host.docker.internal:8097. Docker Desktop forwards that name to the host's loopback address, so a local server such as llama-server keeps listening on 127.0.0.1 only and provider: "local" works through Docker. Change the value in compose.yaml if your local server uses another port.

Stop the non-Docker server first if it is running: both use port 8098.

Retries

The stdio server wraps the provider in RetryingJevProvider, which retries transient failures: rate limiting (429), overload (529), timeouts (including 408 and OpenRouter's 524), HTTP 500/502/503/504 and network errors such as DNS failures. Authentication, authorization, insufficient credits (402), invalid requests and invalid responses are never retried.

Waits use exponential backoff with jitter (up to 0.5 s, then 1 s, 2 s, ..., capped at 8 s). A retry-after header is honored when it is 8 s or less; a longer requested wait ends retrying. Cancellation stops any pending wait. Each retry is logged to stderr. After the last attempt, the original error is returned unchanged.

POST /v1/systemone is retried too. If a timed-out request was actually processed, the retry is billed again.

Each attempt waits at most JEV_TIMEOUT_MS (default 30 s) for the provider. Raise it for slow local servers or large images; a timeout counts as a transient failure and is retried.

Logging

Logs go to stderr; stdout carries only MCP traffic. JEV_LOG_LEVEL picks how much:

Level

Adds

error

Unexpected server errors and startup failures

warn (default)

Retries, and the provider's payload (up to 2,000 characters) when a response is invalid, so the cause can be diagnosed

info

One startup line with the provider, model, timeout, retries and concurrency

debug

One line per provider request: model, number of questions and images, duration, outcome, tokens and reported cost

Logs never contain API keys, Authorization headers or base URLs. debug lines do not include state or question text.

Use with Claude Code

This repository includes a project-scoped .mcp.json that starts dist/transport/stdio.js. After npm run build, start Claude Code in the repository root and approve the jev server when prompted. Check it with /mcp.

Claude Code exposes the tools with dots replaced by underscores, for example mcp__jev__jev_evaluate and mcp__jev__jev_noul.

To use the server from another project, register it with an absolute path:

claude mcp add jev -- node /absolute/path/to/jev-mcp/dist/transport/stdio.js

Tools

jev.evaluate

Evaluates state against a map of questions in one provider request.

{
  "state": "Help! My payouts have been failing for 3 days.",
  "questions": {
    "is_urgent": { "type": "noul", "instructions": "Does this convey urgency?" },
    "department": {
      "type": "choice",
      "instructions": "Which team should handle this?",
      "criteria": { "billing": "Payments, refunds", "technical": "Bugs, outages" }
    },
    "frustration": {
      "type": "score",
      "instructions": "How frustrated is the customer?",
      "criteria": ["Calm", "Frustrated", "Very angry"]
    }
  }
}

model is optional and defaults to JEV_MODEL; surrounding whitespace is removed from it. No other input is changed.

The result has model, answers (keyed by question ID) and usage. Failures come back as tool errors with a kind such as invalid_input, authentication, rate_limited or invalid_response. No answer is ever fabricated.

jev.evaluate_batch

Asks the same questions about many items (up to 100) in one tool call: classify a list of tickets with a choice question, or score every search result and sort by the score. Each item has its own state, optional id and optional images; questions and model work as in jev.evaluate.

{
  "items": [
    { "id": "t1", "state": "My payout failed again." },
    { "id": "t2", "state": "The app crashes when I log in." }
  ],
  "questions": {
    "team": {
      "type": "choice",
      "instructions": "Which team should handle this ticket?",
      "criteria": { "billing": "Payments, refunds", "technical": "Bugs, outages" }
    }
  }
}

The System One APIs take one state per request, so each item is a separate provider request and is billed separately. At most JEV_MAX_CONCURRENCY requests run at the same time.

  • Every item is checked before anything is sent; one invalid item rejects the call.

  • results come back in input order, each with status ok (with answers and usage), error (the item's own error), or skipped.

  • After authentication, authorization, payment_required or configuration errors, items not yet sent are skipped, because they would fail the same way.

  • summary counts each status; usage adds up the successful items, with costUsd only when every successful item reported one.

jev.models

Lists the model names and aliases the provider accepts in model.

jev.noul, jev.choice, jev.score

Convenience tools for a single question. Each takes state, instructions, an optional model and the question's criteria (optional for jev.noul), and returns { model, answer, usage }. They wrap the input in a one-question jev.evaluate request and run it through the same JEV Core path, so validation, answer checks and errors are identical.

{
  "state": "Help! My payouts have been failing for 3 days.",
  "instructions": "Which team should handle this?",
  "criteria": { "billing": "Payments, refunds", "technical": "Bugs, outages" }
}

Use jev.evaluate to ask several questions about the same state: it answers them in one request.

Scripts

Command

Purpose

npm run typecheck

Type-check sources and tests

npm test

Unit tests (no API key needed)

npm run build

Compile to dist/

npm run test:contract

Provider tests against the real TypeSafe API (uses .env)

npm run test:e2e

Build, then drive the stdio server over MCP against the real API

npm start

Start the stdio server

npm run start:http

Start the Streamable HTTP server (needs JEV_HTTP_TOKEN)

scripts\start-http-server.cmd, scripts\stop-http-server.cmd

Windows: double-click to start the HTTP server in a window, or stop it

GitHub Actions (.github/workflows/ci.yml) runs typecheck, test and build on Node 20 and 22 for every push to main and every pull request. It needs no secrets. The contract and e2e suites call the real API and are run locally with a key.

License

MIT

Available Tools

6 tools
jev.choiceChoose an option with JevA
Read-only

Ask TypeSafe Jev to pick one option for some state. criteria maps option names to descriptions (or null), up to 255 options; include a "none" option when nothing may fit. Returns answer.choice, answer.probabilities per option and answer.confidence.

state is the content to judge (a string, or a JSON object/array). instructions must state the full question; refer to parts of structured state with backticked paths such as ticket.messages[0].text. model is optional. images (optional, up to 4 PNG, JPEG or WebP, 4 MiB each) are judged together with state; each is either { "path": "" } for a local file inside a directory the server allows (JEV_IMAGE_DIRS), or { "data": "data:image/png;base64,..." }. Only image-capable models accept images (for example cloudflare/clef or cloudflare/clef-flash through OpenRouter); other models reject them. Never put images inside state. To ask several questions about the same state, use jev.evaluate instead: it answers them in one request. provider is optional; this server offers only "typesafe".

NameRequiredDescriptionDefault
modelNo
stateYes
imagesNo
criteriaYes
providerNo
instructionsYes

Output Schema

NameRequiredDescription
modelYesThe model that answered, usually a versioned ID
usageYes
answerYes
providerNoThe provider that answered

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already cover read-only and open-world traits, and the description adds return shape (`answer.choice`, `answer.probabilities`, `answer.confidence`), a hard limit of 255 options, image size/format limits of 4 images, PNG/JPEG/WebP, 4 MiB each, and the model-capability rejection behavior. It doesn't describe failure modes for oversized criteria or missing model access, but the constraints it does disclose go well beyond the annotations.

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 purpose and the return values are front-loaded, then parameters follow in a logical order. It is dense and packs image-handling detail into one long sentence, but essentially every clause — limits, path constraints, model capability — is load-bearing rather than filler.

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 6-parameter tool with nested objects and an output schema, the description covers what the output schema cannot say on its own: the option cap, the 'none' pattern, the image rules and the single-question scope. Nothing an agent needs to invoke it correctly is missing.

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?

With 0% schema description coverage the description must carry the whole burden, and it does: `criteria` is explained as a name-to-description map (or null), `state` as string or structured JSON, `instructions` as the full question with backticked paths like `ticket.messages[0].text`, and `images` entries as either a path inside JEV_IMAGE_DIRS or a base64 data URL.

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 opening sentence states a specific verb and resource: 'Ask TypeSafe Jev to pick one option for some state', which tells an agent exactly what the tool produces. It is clearly separable from jev.evaluate, the multi-question sibling, which is named later in the text.

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?

Explicit routing rules are given: 'include a "none" option when nothing may fit' and 'To ask several questions about the same state, use jev.evaluate instead'. It also states that only image-capable models accept images and that other models reject them, so the agent knows when this call should not be made.

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

jev.evaluateEvaluate with JevA
Read-only

Ask TypeSafe Jev typed questions about a piece of state and get calibrated probabilities back.

Send the content to judge as state (a string, or a JSON object/array for structured data) and a map of questions keyed by IDs you choose. All questions are answered in parallel against the same state, in one request, and cannot see each other's answers.

Question types:

  • noul: a yes/no question. Returns noul, the probability of yes (0..1). Optional criteria { true, false } describes what yes and no mean.

  • choice: pick one option. criteria maps option names to descriptions (or null), up to 255 options. Returns choice, probabilities per option and confidence.

  • score: rate along ordered levels. criteria is an array of 2-10 level descriptions, lowest first. Returns score (a probability-weighted level index from 0, may fall between levels), legend, probabilities and confidence.

Question IDs are not shown to the model, so instructions must state the full question. Refer to parts of structured state with backticked paths such as ticket.messages[0].text. Ask one narrow judgment per question. model is optional and defaults to the server's configured model.

images (optional, up to 4 PNG, JPEG or WebP, 4 MiB each) are judged together with state; each is either { "path": "" } for a local file inside a directory the server allows (JEV_IMAGE_DIRS), or { "data": "data:image/png;base64,..." }. Only image-capable models accept images (for example cloudflare/clef or cloudflare/clef-flash through OpenRouter); other models reject them. Never put images inside state.

provider is optional; this server offers only "typesafe".

NameRequiredDescriptionDefault
modelNo
stateYes
imagesNo
providerNo
questionsYes

Output Schema

NameRequiredDescription
modelYesThe model that answered, usually a versioned ID
usageYes
answersYesOne answer per question ID
providerNoThe provider that answered

TDQS

A4.5/5.0
Behavior5/5

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

Goes well beyond readOnlyHint/openWorldHint: questions run in parallel against the same state and cannot see each other's answers, provider is restricted to "typesafe", and images must live under JEV_IMAGE_DIRS or be inline data URLs with a 4 MiB cap and image-capable-model requirement. Those are exactly the behavioral facts an agent would otherwise discover by failing.

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?

Front-loads the core purpose, then uses a bulleted question-type block, then tacks on optional concerns (images, provider). Dense and mostly waste-free, though the question-type bullets partially duplicate what the output schema already declares.

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 5-parameter tool with deeply nested question objects, the description covers the state/questions interaction, per-type criteria contracts, model/image constraints, and even summarizes return fields despite an output schema existing. An agent has everything needed to construct a valid call on the first try.

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 description coverage is 0%, so the description carries the full load and does so thoroughly: `state` as string or JSON, `questions` as an ID-keyed map with the three variants and their criteria shapes and limits (255 options, 2-10 levels), `images` formats and sources, `model` default, and `provider` restriction. Little about the parameters is left ambiguous.

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

Purpose4/5

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

States a specific verb and resource: ask typed questions about a piece of state, get calibrated probabilities back. That is far more precise than a name restatement. It does not, however, differentiate itself from siblings jev.noul, jev.choice, jev.score or jev.evaluate_batch, so an agent must infer that this is the multi-question, multi-type entry point.

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

Usage Guidelines4/5

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

Offers concrete operating guidance: one narrow judgment per question, question IDs are invisible to the model so `instructions` must be self-contained, backticked paths for structured state, never place images inside `state`, and images require an image-capable model. It stops short of saying when to prefer this over jev.noul / jev.choice / jev.score / jev.evaluate_batch.

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

jev.evaluate_batchEvaluate many items with JevA
Read-only

Ask TypeSafe Jev the same typed questions about many items (up to 100) in one call, for example to classify a list of tickets or to score every search result and sort them.

items is a list of { "state": ..., "id"?: "...", "images"?: [...] }; each item is judged on its own. questions and the optional model work exactly as in jev.evaluate and apply to every item. Use a choice question to classify, a score or noul question to rank, and several questions to tag.

Each item is a separate provider request and is billed separately. Every item is checked before anything is sent; one invalid item rejects the whole call. Returns results in input order: status "ok" with answers and usage, "error" with the item's own error, or "skipped" when an earlier error (for example authentication or no credits) would also have hit it. summary counts each status and usage adds up the successful items.

images (optional, up to 4 PNG, JPEG or WebP, 4 MiB each) are judged together with the item's state; each is either { "path": "" } for a local file inside a directory the server allows (JEV_IMAGE_DIRS), or { "data": "data:image/png;base64,..." }. Only image-capable models accept images (for example cloudflare/clef or cloudflare/clef-flash through OpenRouter); other models reject them. Never put images inside state.

provider is optional; this server offers only "typesafe".

NameRequiredDescriptionDefault
itemsYes
modelNo
providerNo
questionsYes

Output Schema

NameRequiredDescription
usageYesSum over successful items; costUsd only when every successful item reported a cost
resultsYesOne result per item, in input order
summaryYes
providerYesThe provider every item was sent to

TDQS

A4.7/5.0
Behavior5/5

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

Goes well beyond readOnlyHint/openWorldHint: discloses per-item billing, all-or-nothing pre-validation ('one invalid item rejects the whole call'), per-item ok/error/skipped statuses with the auth/no-credits cascade rule, and image model capability limits. This is exactly the operational context an agent cannot infer from annotations.

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?

Front-loaded with purpose and usage patterns, then parameters, then provider. Dense but nearly every sentence adds a constraint; the paragraph on image models and the JEV_IMAGE_DIRS aside could be tightened slightly.

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?

Output schema exists, yet the description still summarizes `results`/`summary`/`usage` shapes in a way that clarifies ordering and status semantics. Together with the image, validation, and billing rules, an agent has everything needed to call this correctly on the first try.

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 description coverage is 0%, so the description carries the full burden and does so: it documents the `items` element shape, the optional `id`, the two image forms with size/format caps and the JEV_IMAGE_DIRS restriction, that `provider` only accepts 'typesafe', and that images must never be nested in `state`. These are non-obvious constraints absent from the schema.

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 — 'Ask TypeSafe Jev the same typed questions about many items (up to 100) in one call' — and names the motivating use cases (classify tickets, score and sort search results). The batch-vs-single distinction from jev.evaluate is made explicit via the reference that questions/model 'work exactly as in jev.evaluate'.

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

Usage Guidelines4/5

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

Gives concrete routing advice: use a choice question to classify, a score or noul question to rank, several questions to tag, and points to jev.evaluate for parameter semantics. It doesn't state an explicit exclusion (e.g. 'use jev.evaluate for a single item'), but the one-call/up-to-100 framing makes the boundary obvious.

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

jev.modelsList Jev modelsA
Read-only

List the model names and aliases each provider accepts in the model field, tagged with their provider. Pass provider to list one provider only. A provider that cannot be reached appears in errors instead of failing the whole list. provider is optional; this server offers only "typesafe".

NameRequiredDescriptionDefault
providerNo

Output Schema

NameRequiredDescription
errorsNoProviders whose model list could not be read
modelsYes

TDQS

A4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint and openWorldHint, so the description adds real value beyond them: it discloses partial-failure behavior — an unreachable provider surfaces in `errors` rather than failing the whole call. It stops short of describing ordering, pagination, or size of the result set.

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 output shape and filtering behavior are front-loaded and every clause carries information. There is mild redundancy between "Pass `provider` to list one provider only" and "`provider` is optional", which keeps it from a 5.

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?

With an output schema present, the description needn't enumerate return fields, and it still calls out the key edge case (`errors`). For a zero-required-parameter read tool this is close to complete; only result-volume or sorting behavior is unaddressed.

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?

Schema coverage is 0%, so the description must carry the meaning of `provider`. It does: the parameter is optional, narrows output to a single provider, and the only valid value on this server is "typesafe" — enough for an agent to supply or omit it correctly.

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

Purpose4/5

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

The description gives a specific verb and resource: list model names and aliases per provider, tagged with `provider`, that can be used in the `model` field. It is clearly distinct from the sibling evaluation tools (jev.evaluate, jev.score) by resource, though it never names a sibling explicitly.

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

Usage Guidelines4/5

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

It tells the agent when to pass `provider` (to list one provider only) and that omitting it is fine because the server offers only "typesafe". There are no stated exclusions or named alternatives, but for a single-parameter list tool the usage context is clear.

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

jev.noulYes/no question with JevA
Read-only

Ask TypeSafe Jev one yes/no question about some state. Returns answer.noul, the probability of yes (0..1); 0.5 means equally likely, not "medium". Optional criteria { true, false } describes what yes and no mean.

state is the content to judge (a string, or a JSON object/array). instructions must state the full question; refer to parts of structured state with backticked paths such as ticket.messages[0].text. model is optional. images (optional, up to 4 PNG, JPEG or WebP, 4 MiB each) are judged together with state; each is either { "path": "" } for a local file inside a directory the server allows (JEV_IMAGE_DIRS), or { "data": "data:image/png;base64,..." }. Only image-capable models accept images (for example cloudflare/clef or cloudflare/clef-flash through OpenRouter); other models reject them. Never put images inside state. To ask several questions about the same state, use jev.evaluate instead: it answers them in one request. provider is optional; this server offers only "typesafe".

NameRequiredDescriptionDefault
modelNo
stateYes
imagesNo
criteriaNo
providerNo
instructionsYes

Output Schema

NameRequiredDescription
modelYesThe model that answered, usually a versioned ID
usageYes
answerYes
providerNoThe provider that answered

TDQS

A4.7/5.0
Behavior5/5

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

Annotations only say readOnlyHint/openWorldHint; the description adds substantial context beyond them: the 0..1 probability scale and the trap reading of 0.5, the 4-image / 4 MiB / PNG-JPEG-WebP limits, the JEV_IMAGE_DIRS sandbox for path inputs, the base64 data-URL form, the warning never to put images inside `state`, and model capability rejection behavior.

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?

Front-loaded with purpose and return semantics before parameter detail, and nearly every sentence carries non-obvious information. It is a dense block rather than a scannable structure, and the image/model constraints bleed into what would otherwise be a clean parameter walkthrough.

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?

An output schema exists, so the return value needn't be re-explained, and annotations cover the safety profile; the description fills the real gaps (image sandboxing, model capability, state/instructions discipline). The only missing piece for correct invocation is guidance on choosing `model` rather than leaving it as a bare 'optional'.

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?

Schema coverage is 0%, so the description must carry the load, and it mostly does: `state` (string or JSON object/array), `instructions` (must state the full question, reference structured state via backticked paths like `ticket.messages[0].text`), `criteria` {true,false}, `images` (both shapes with limits), and `provider`. The gap is `model`, which is only called 'optional' with no guidance on valid values or how to discover them (jev.models exists), which matters given the image-capability constraint.

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 ('Ask TypeSafe Jev one yes/no question about some state') and immediately defines the return semantics as `answer.noul`, a probability 0..1 with 0.5 = equally likely. It also distinguishes itself from the sibling `jev.evaluate` by scoping to a single question, so an agent can pick between them without opening the schema.

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?

Gives an explicit routing rule: 'To ask several questions about the same state, use jev.evaluate instead: it answers them in one request.' It also states when-not conditions for images (only image-capable models, names concrete examples) and notes the server only offers provider 'typesafe', leaving no ambiguity about alternatives.

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

jev.scoreScore on a scale with JevA
Read-only

Ask TypeSafe Jev to rate some state along ordered levels. criteria is an array of 2-10 level descriptions, lowest first. Returns answer.score (a probability-weighted level index from 0, may fall between levels), answer.legend, answer.probabilities and answer.confidence.

state is the content to judge (a string, or a JSON object/array). instructions must state the full question; refer to parts of structured state with backticked paths such as ticket.messages[0].text. model is optional. images (optional, up to 4 PNG, JPEG or WebP, 4 MiB each) are judged together with state; each is either { "path": "" } for a local file inside a directory the server allows (JEV_IMAGE_DIRS), or { "data": "data:image/png;base64,..." }. Only image-capable models accept images (for example cloudflare/clef or cloudflare/clef-flash through OpenRouter); other models reject them. Never put images inside state. To ask several questions about the same state, use jev.evaluate instead: it answers them in one request. provider is optional; this server offers only "typesafe".

NameRequiredDescriptionDefault
modelNo
stateYes
imagesNo
criteriaYes
providerNo
instructionsYes

Output Schema

NameRequiredDescription
modelYesThe model that answered, usually a versioned ID
usageYes
answerYes
providerNoThe provider that answered

TDQS

A4.7/5.0
Behavior5/5

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

Annotations only declare readOnlyHint and openWorldHint, but the description adds real behavioral context: image constraints (max 4, PNG/JPEG/WebP, 4 MiB each), the JEV_IMAGE_DIRS sandbox for path-based images, the fact that only image-capable models accept images and others reject them, and that the only supported provider is 'typesafe'. It even discloses the return shape, including that scores are probability-weighted and may fall between levels.

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?

Front-loaded with the core operation and return shape, then parameter guidance, then the sibling routing hint — a sensible order. It is dense and a few clauses (base64 data URL format, per-format repetition of PNG/JPEG/WebP) duplicate what the schema already documents, so it is somewhat longer than strictly necessary.

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?

An output schema exists, yet the description still names the key return fields (answer.score, answer.legend, answer.probabilities, answer.confidence), which helps an agent interpret the probability-weighted index. Combined with the model/provider caveats and image rules, nothing essential for a correct invocation is missing.

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 description coverage is 0%, but the description compensates for every parameter: `state` (string or JSON object/array), `instructions` (must state the full question, use backticked paths into structured state), `criteria` (2-10 ordered levels), `model` and `provider` (both optional, provider restricted to 'typesafe'), and both image forms with their required keys. It also gives a concrete path syntax example, which the schema does not.

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 — rate a state along ordered levels — and immediately pins down what `criteria` means (2-10 level descriptions, lowest first). It also names the sibling it is not for the multi-question case, so an agent can distinguish it from jev.evaluate without opening either schema.

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

Usage Guidelines4/5

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

Explicit routing guidance: 'To ask several questions about the same state, use jev.evaluate instead' gives a clear when-to-use-the-alternative rule, and the image/model compatibility note warns when this tool cannot be used. It does not address jev.choice or jev.evaluate_batch, which are plausible nearer alternatives for single-label judgement or multiple states.

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. 6 tool updatesv0.6.0
    • First observedjev.choice
    • First observedjev.evaluate
    • First observedjev.evaluate_batch
    • First observedjev.models
    • First observedjev.noul
    • First observedjev.score

TDQS

A4.4/5.0

Scored across 6 tools

Disambiguation4/5

The boundaries are mostly clear: `evaluate` handles multiple questions over one state, `evaluate_batch` handles many items, and `noul`/`choice`/`score` are single-question shortcuts per question type. However, `noul`, `choice`, and `score` are strict subsets of `evaluate`'s capability, so an agent could justifiably always use `evaluate` and ignore the other three; the descriptions acknowledge this overlap but don't fully eliminate the redundancy.

Naming Consistency4/5

All names are namespaced under `jev.` and use consistent snake_case (`evaluate_batch` matches `evaluate`). The only deviation is that `evaluate`/`evaluate_batch` are verbs while `models`, `noul`, `choice`, and `score` are nouns naming question types, which is readable but not a single uniform verb_noun pattern.

Tool Count5/5

Six tools is well-scoped for an LLM-judge service: one general evaluate, one batch, one discovery tool, and three typed convenience wrappers. Every tool maps to a distinct use case and none feels like filler.

Completeness4/5

The surface covers the full evaluation lifecycle: single state, batch, model discovery, and all three question types (yes/no, choice, score), including image and structured-state support. Minor gaps exist—no tool to inspect the configured provider/model default, check credit or usage status ahead of a run, or resume partially failed batches.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables agents and services to ask small decision models typed questions about text, JSON, images, or video, returning labels, scores, or yes/no answers over MCP tools or a Jev-compatible HTTP API.
    Apache 2.0
  • A
    license
    A
    quality
    A
    maintenance
    Enables coding agents to request calibrated probability judgments over typed questions—yes/no, named choices, or ordered scores—about a described situation, returning one probability per option rather than free text. Runs Cloudflare's Clef model locally on Apple Silicon Macs, with images or video frames optionally attached, and answers delivered as a single MCP tool call.
    1
    123 PyPI
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    An MCP server that answers typed noul/choice/score questions about a given state with probability distributions and confidence, for routing, escalation, and gating decisions. It runs on pluggable backends (local Needle 3 or Laya models, or any OpenAI-compatible endpoint) and logs every decision so recorded ground truth can be used to track calibration.
    3
    MIT