jev-mcp
Provides integration with Cloudflare Clef decision models, allowing MCP clients to ask typed yes/no, choice, and score questions about structured state and receive calibrated probabilities. Supports image inputs for Clef models with count, format, and size limits.
Provides integration with OpenAI's Decisions API in public beta through the openai/gpt-6-luna-decisions model, enabling typed decision questions over structured state and images, with calibrated probabilities and refusal reporting.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@jev-mcpAsk Jev if this support ticket is urgent: yes/no with a calibrated probability."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
jev-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 OpenRouterSee 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 buildVariable | Required | Default |
| no |
|
| no | unset: only |
| when | — |
| no |
|
| when | — |
| no |
|
| no |
|
| no | unset: no Authorization header |
| no |
|
| no |
|
| no | unset: image |
| no |
|
| no |
|
| no |
|
| no |
|
| for | — (at least 32 characters; see Streamable HTTP) |
| no |
|
| no |
|
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 | 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, | 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.
| Models ( | Cost in results |
|
| not reported |
|
|
|
| Whatever your local System One server serves, for example | 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,localEvery 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, onlyJEV_PROVIDERis used, even if other keys are set.JEV_MODELapplies to the default provider. A request that selects TypeSafe or a local server without amodelusesjev-latest; OpenRouter needs an explicitmodel, such ascloudflare/clef-flashortypesafe/jev-1.13.An unknown
provideris 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 |
| Agents on the same machine (Claude Code, Codex, VS Code) | Absolute path inside a |
| 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 containercompose.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 |
| Unexpected server errors and startup failures |
| Retries, and the provider's payload (up to 2,000 characters) when a response is invalid, so the cause can be diagnosed |
| One startup line with the provider, model, timeout, retries and concurrency |
| 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.jsTools
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.
resultscome back in input order, each withstatusok(withanswersandusage),error(the item's own error), orskipped.After
authentication,authorization,payment_requiredorconfigurationerrors, items not yet sent areskipped, because they would fail the same way.summarycounts each status;usageadds up the successful items, withcostUsdonly 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 |
| Type-check sources and tests |
| Unit tests (no API key needed) |
| Compile to |
| Provider tests against the real TypeSafe API (uses |
| Build, then drive the stdio server over MCP against the real API |
| Start the stdio server |
| Start the Streamable HTTP server (needs |
| 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
Available Tools
6 toolsjev.choiceChoose an option with JevARead-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".
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | ||
| state | Yes | ||
| images | No | ||
| criteria | Yes | ||
| provider | No | ||
| instructions | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| model | Yes | The model that answered, usually a versioned ID |
| usage | Yes | |
| answer | Yes | |
| provider | No | The provider that answered |
TDQS
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.
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.
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.
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.
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.
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 JevARead-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). Optionalcriteria{ true, false } describes what yes and no mean.choice: pick one option.
criteriamaps option names to descriptions (or null), up to 255 options. Returnschoice,probabilitiesper option andconfidence.score: rate along ordered levels.
criteriais an array of 2-10 level descriptions, lowest first. Returnsscore(a probability-weighted level index from 0, may fall between levels),legend,probabilitiesandconfidence.
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".
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | ||
| state | Yes | ||
| images | No | ||
| provider | No | ||
| questions | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| model | Yes | The model that answered, usually a versioned ID |
| usage | Yes | |
| answers | Yes | One answer per question ID |
| provider | No | The provider that answered |
TDQS
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.
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.
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.
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.
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.
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 JevARead-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".
| Name | Required | Description | Default |
|---|---|---|---|
| items | Yes | ||
| model | No | ||
| provider | No | ||
| questions | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| usage | Yes | Sum over successful items; costUsd only when every successful item reported a cost |
| results | Yes | One result per item, in input order |
| summary | Yes | |
| provider | Yes | The provider every item was sent to |
TDQS
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.
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.
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.
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.
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.
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 modelsARead-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".
| Name | Required | Description | Default |
|---|---|---|---|
| provider | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| errors | No | Providers whose model list could not be read |
| models | Yes |
TDQS
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.
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.
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.
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.
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.
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 JevARead-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".
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | ||
| state | Yes | ||
| images | No | ||
| criteria | No | ||
| provider | No | ||
| instructions | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| model | Yes | The model that answered, usually a versioned ID |
| usage | Yes | |
| answer | Yes | |
| provider | No | The provider that answered |
TDQS
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.
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.
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.
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.
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.
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 JevARead-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".
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | ||
| state | Yes | ||
| images | No | ||
| criteria | Yes | ||
| provider | No | ||
| instructions | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| model | Yes | The model that answered, usually a versioned ID |
| usage | Yes | |
| answer | Yes | |
| provider | No | The provider that answered |
TDQS
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.
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.
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.
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.
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.
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.
6 tool updates
v0.6.0- First observed
jev.choice - First observed
jev.evaluate - First observed
jev.evaluate_batch - First observed
jev.models - First observed
jev.noul - First observed
jev.score
TDQS
Scored across 6 tools
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.
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.
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.
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
Related MCP Connectors
A paid remote MCP for Pydantic AI structured output, built to return verdicts, receipts, usage logs,
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
A paid remote MCP for Skybridge, built to return verdicts, receipts, usage logs, and audit-ready JSO
A paid remote MCP for HyperFrames, built to return verdicts, receipts, usage logs, and audit-ready J
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables running Jev AI typed decisions from any MCP client, returning choices, scores, or yes/no with calibrated probabilities.312 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables 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
- AlicenseAqualityAmaintenanceEnables 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.1123 PyPIMIT
- AlicenseAqualityCmaintenanceAn 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.3MIT