MCP reference

Status: draft. judgevet-mcp requires the optional mcp extra. It serves MCP over stdio: stdout is protocol traffic and stderr is diagnostics. For installation, host configuration and discovery, use Connect MCP.

Tool arguments

The three ask_* tools take these arguments. All require state and instruction (singular). instruction is a string. The published schema allows a string or object for state.

Tool Additional argument Default when omitted
ask_noul None No criteria argument is exposed.
ask_choice criteria: object mapping labels to descriptions {"yes":"Yes","no":"No"}
ask_score criteria: ordered levels, lowest first, of the property the question asks about, such as ["Not urgent","Low","Medium","High","Critical"] for urgency ["Poor","Fair","Good","Excellent"], a generic quality rubric

The tool definitions are the source for these local schemas. ask_noul, ask_choice and ask_score accept a string or an object for state. They do not accept an array. evaluate_policy accepts a string, an object or an array for state. Each ask tool schema sets additionalProperties: false. The ask tool schemas do not specify item/value schemas for criteria. Handlers are not a substitute for full schema validation.

Each tool constructs one named question and calls the sync port with the host-selected model, which defaults to "jev-latest". The installed judgevet-mcp command takes the host-selected model from JEV_API__DEFAULT_MODEL. Tool arguments cannot select a model or acceptance policy. The internal question names are noul_question, choice_question and score_question. Host argument instruction becomes wire instructions. See configuration overrides.

Tool titles and annotations

Each tool publishes a display title and two annotations in tools/list.

Tool title
ask_noul Ask a yes/no judgment
ask_choice Ask a multiple-choice judgment
ask_score Ask a scored judgment
evaluate_policy Evaluate a judgment policy

Every tool sets readOnlyHint: true, because a judgment changes no environment state. Every tool sets openWorldHint: true, because the call reaches an outside judgment model through the configured provider. judgevet omits destructiveHint and idempotentHint. The specification gives them meaning only when readOnlyHint is false. All annotations are hints. A client must not trust them from an untrusted server. Source: https://modelcontextprotocol.io/specification/2026-07-28/schema. Source: https://modelcontextprotocol.io/specification/2026-07-28/server/tools.

Server instructions

The initialize result carries instructions. A client may add this text to the model's system prompt. The specification says the text should help the model use the server and should not repeat the tool descriptions. judgevet sends this default text, 108 words and 730 characters, pinned in tests/fixtures/mcp_contract.json:

judgevet answers judgment questions about a state. Each call sends the state to the configured judgment backend. Send no secret. Pick the tool by the decision. Use ask_noul to test one proposition. Use ask_choice to pick one of several unordered labels. Use ask_score to place the state on ordered levels. Use evaluate_policy to ask several questions under one acceptance rule. Write criteria that define each label or level in plain terms. Vague labels give vague answers. A probability or a confidence is not measured accuracy. The caller decides what to do with an answer. Each tool refuses unknown arguments. Send only the declared fields. Question design guide: https://alberto-codes.github.io/judgevet/explanation/judgments/

The default text states no limits of use. A consumer states its own limits of use with the instructions argument of mcp_entrypoint.main, run_stdio or create_mcp_server. That text replaces the default text. The hosted judgevet-mcp command sends the default text. A non-string instructions value raises TypeError before serving starts.

A self-hosted launcher may also pass instructions_addendum. The server appends it after the default or replacement text and one blank line. A non-string addendum raises TypeError before serving starts. Source: https://modelcontextprotocol.io/specification/2026-07-28/schema.

In this example, a support team's launcher calls main(instructions=INSTRUCTIONS) with the text below. The text states the team's limits of use first and keeps the tool guidance the team needs:

judgevet answers judgment questions about support tickets. Each call sends the ticket text to the configured judgment backend. Use these tools only to route tickets to a queue. Do not use them to judge a person's credit, health or employment. Remove names, account numbers and other personal data first. Use ask_choice to pick the queue. The caller decides what to do.

Claude Code truncates each server's instructions at 2,048 characters by default and advises putting critical details near the start. From Claude Code v2.1.280, the CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH environment variable changes that limit. A test holds the default text under 1,500 characters. Keep a replacement and its addendum under the client's limit, and put the limits of use first. Source: https://code.claude.com/docs/en/mcp.md.

Successful answers

A successful call returns structured content and one text content item. The text is that structured content serialized as JSON, so parsing the text gives the same object. Source: structured content. Python SDK attributes use structured_content and is_error; wire JSON fields use structuredContent and isError. This distinction is recorded in the adapter's SDK citations.

Tool Structured fields
ask_noul noul, model, usage
ask_choice choice, confidence, probabilities, model, usage
ask_score score, confidence, probabilities, legend, default_criteria, model, usage

usage contains input_tokens and output_tokens. default_criteria is a boolean. It is true when the call omitted criteria and the server applied the default ["Poor", "Fair", "Good", "Excellent"]. It is false when the caller supplied criteria, including a list equal to the default. Sources: issue #228 decision and AIP-129. Structured content contains the single answer's fields directly, not the CLI's answers envelope. JSON object keys for Score levels are strings on the wire. Field semantics and vendor citations are in the Python API reference. A host that shows only text shows this JSON. A successful call is a judgment, not evidence of its correctness.

Release 0.14.0 and later declare an outputSchema for each of the four tools. Each schema is a closed JSON Schema 2020-12 object that matches the fields in the table above and, for evaluate_policy, the result described below. Every field carries a description. A token count in usage is an integer or null. Error results carry no structured content, and the schemas do not cover them. The output schemas are the source. Releases before 0.14.0 declare no output schemas. Source: output schema rules.

Keyed policy tool

Release 0.14.0 adds evaluate_policy to discovery.

Pass required state, questions and policy, with optional evidence. State accepts a string, object or array. Questions use the CLI JSON grammar, keyed by caller IDs. Each question accepts only type, instructions and criteria; unknown fields produce an error before dispatch. Optional Noul criteria pass through unchanged. Choice and score questions need criteria. A choice question takes a non-empty object of labels. A score question takes a non-empty array of levels, lowest first. The defaults of ask_choice and ask_score do not apply here. The question schema declares this rule with nested if and then conditionals. The handler also rejects a question without valid criteria, because not every client validates the input schema. Source: https://github.com/Alberto-Codes/judgevet/issues/305. Policy uses the public policy JSON grammar. The policy schema declares that grammar as closed JSON Schema 2020-12 objects, with a nested anyOf for pass and one example in its description. A score answer is the probability-weighted expected level, a continuous value. A score predicate takes min and max bounds on that value, or {"level": integer} for an exact match on the highest-probability level, as in {"rules":[{"question":"s","pass":{"score":{"level":1}}}]}. The level form excludes min and max. The handler still checks bound order, question-relative ranges, boolean bounds, duplicate keys and the exclusion of level with a bound. An unknown-field error names the first unknown key in sorted order, shortened to 64 characters, and the allowed keys. The application selects the model; a model argument is rejected before dispatch. Invalid definitions also fail before dispatch.

Success returns matching JSON text and structured content with model, usage, answers and policy. The policy object contains result (pass or fail) and ordered rules with question, pass and detail. An unmet policy has isError: false. Invalid input, invalid policy answers and declared provider failures have isError: true, without fabricated answers or a verdict. Unexpected implementation errors retain SDK handling. Provider error messages must be safe for the application to disclose. Unknown usage stays null.

The tool uses strict public policy evaluation. Existing CLI semantics remain unchanged. Provider selection does not install audit or spend controls. Providers that opt into those controls retain their own accounting and records. Source: keyed policy contract.

Failure and lifecycle behavior

The ask tools check their arguments before any provider call. A missing state or instruction returns a tool result with isError true and the text Missing required argument: <name>. ask_choice criteria must be a non-empty object, and ask_score criteria must be a non-empty array, when given. Wrong criteria return the same kind of tool result. An argument the tool schema does not declare returns Unknown arguments: <names>, with every unknown name in sorted order. ask_noul declares no criteria, so criteria is unknown there. The handlers check this because not every client validates the input schema. Source: https://github.com/Alberto-Codes/judgevet/issues/303. The MCP tools specification classifies input validation errors as tool execution errors; see error handling.

An unknown tool and a missing expected answer raise ValueError in the handlers. A wrong answer variant raises TypeError. A declared service error from any tool returns a tool result with isError true and the error text. With evidence, evaluate_policy reports only the error type, as <Type>: media evaluation failed. A tool failure is not a negative Noul answer or an unmet policy.

A tripped spend cap returns a tool result with isError true on every tool, the media path included. Its text names the limit and says a restart is required. An example is Spend cap reached: attempts spent 2 of 2; restart the server to continue.. The cap lasts for the server's lifetime and never resets, so a retry cannot succeed until the host restarts the server. Do not assume error text has been scrubbed; see diagnostic limits.

The entry point constructs and closes the adapter around serving. It returns 2 for missing runtime, invalid settings or missing key, and 130 for keyboard interruption. With JEV_API__AUDIT_PATH set, it opens the audit file first and closes it after the adapter. A fatal failure exits 1 and names its stage: audit sink, credential resolution, provider acquisition, serving or shutdown. A sink that cannot open reports judgevet-mcp: audit sink failed (<TypeName>). See fatal diagnostics. EOF ends the stdio session. The tested SDK baseline and legacy initialization path are recorded in the adapter source; an unexercised protocol path is not promoted by those tests. Intermittent host initialization failures have no established remedy; use connection checks.

For embedding, create_mcp_server(port) accepts a SystemOnePort. The factory does not construct or close the caller's port. This entry point stays in the optional inbound adapter; importing the base library does not require MCP.

Application-selected providers

create_mcp_server(port, *, model="jev-latest", instructions=None, instructions_addendum=None) borrows a provider and accepts an explicit host-selected model. run_stdio accepts the same arguments. mcp_entrypoint.main accepts keyword-only port, provider_factory, model, instructions and instructions_addendum. Supply either a borrowed port or an owning factory. Supplying both raises ValueError before acquisition. Explicit selection skips hosted settings and credentials. Omission retains the hosted command and its configuration.

The server serializes synchronous calls on a worker thread. The event loop remains available while a provider runs. Cancellation removes queued calls before dispatch. A running call finishes before cancellation propagates, even when cancellation repeats. Factory acquisition, calls and cleanup share one worker thread. Session exit shuts down that worker. Borrowed ports remain open. Direct registered-handler calls outside a server lifespan use temporary workers. Applications own provider deadlines; cancellation cannot kill synchronous work.

Declared provider failures cross the entrypoint's existing safe diagnostic boundary. Provider selection adds no audit sink, spend cap or redaction. Applications configure those controls on their providers. Source: MCP provider contract.

Image evidence

evaluate_policy accepts optional evidence as a JSON text string. The embedded object contains images, by_question and optional required. Each image contains exactly id, data_base64 and media_type. data_base64 carries standard ASCII base64 of the original encoded image bytes. by_question maps question IDs to ordered image IDs. required lists questions that must have images. The provider receives original byte order and per-question associations.

The adapter rejects duplicate embedded keys, non-finite constants, unknown fields, invalid base64 and invalid associations. Already-decoded objects are invalid. The JSON text ceiling is 48 MiB UTF-8. Limits are 16 images, 8 MiB per image and 32 MiB decoded bytes in total. Provider capabilities can reduce these limits. The adapter reads no paths or URLs and does not decode image formats. Omitting evidence or supplying valid empty optional evidence retains text routing. The hosted provider does not implement image evidence.

Decoding, validation and inference share the existing serialized worker. Canceled queued calls submit no work. Canceled running calls drain before owned cleanup. Acquisition can precede request validation because it belongs to the serving session. Media failures return isError: true with a neutral error class and safe category, without answers, policy verdicts or payload diagnostics. An explicitly declared insufficient-evidence Choice remains an ordinary answer and can produce an unmet policy. Success preserves model and usage metadata.

Source: MCP media contract.