Skip to main content
LLMs are probabilistic, so the same prompt might produce different results each time. Running a test once tells you it can work, not that it reliably works. Evals run the same test many times and measure statistical accuracy.

Why Run Evals?

A single test pass can be misleading:
  • The LLM might get lucky on one attempt
  • Temperature introduces randomness
  • Different phrasings might fail where others succeed
Running 30+ iterations gives you confidence in real-world performance:
  • “This tool is called correctly 97% of the time”
  • “Arguments are correct in 90% of cases”
  • “Average latency is 1.2 seconds”

EvalTest: Single Test Scenario

EvalTest runs one test function multiple times:

Writing Test Functions

Test functions receive an HostExecutor (implemented by HostRunner and mock agents) and return boolean:

Run Options

Metrics

After running, access various metrics:

EvalSuite: Multiple Tests

Group related tests together:

Save Results to MCPJam

Both EvalTest and EvalSuite can automatically save results to MCPJam when a run completes. Set MCPJAM_API_KEY to an MCPJam API key (sk_…) from Settings → API keys and results are saved automatically:
Results are filed under the project in MCPJAM_PROJECT_ID (or the project option), defaulting to your organization’s Default project. For manual save APIs, CI metadata, and artifact uploads, see the Save Results to MCPJam guide.

Tool errors vs. passed on upload

By default, when results are built from traces (auto-save and reporter helpers), a failed tool execution (MCP isError, errored tool spans, or error tool-results in messages) sets passed: false for that iteration even if your test function returned true. That keeps CI pass rate aligned with real server behavior. To disable that for a run (for example you only assert which tools were called, not that every call succeeded), set failOnToolError: false on the mcpjam block:
See Eval reporting — Tool execution and passed for full detail and createEvalRunReporter overrides.

Predicate gate

Predicates express richer pass/fail criteria than tool-call matching — without an LLM judge. Each predicate is a pure function of the iteration transcript, so it produces the same verdict every time, which makes it safe to use as a CI release gate. Predicates are authored in the corpus JSON (the Inspector’s per-case Checks editor writes the same shape) and threaded through the runner automatically; there is no predicate field to set on individual uploaded results. A case passes iff all predicates pass. An absent or empty list means no predicate gate. The twelve built-in predicate types: When an iteration records no widget render observations, the three widget* predicates fail rather than pass — a missing signal counts as a failure. See Predicate gate reference for the full type definitions and a code example.

Suite Results

Choosing Iteration Count

Best Practices

Use Low Temperature

More deterministic results for testing:

Handle Rate Limits

Reduce concurrency for rate-limited APIs:

Test Edge Cases

Don’t just test the happy path:

Set Quality Thresholds

Fail CI if accuracy drops below a threshold:

Bring your own host

HostRunner is the right starting point when you just need an LLM + tools + a model string. For richer setups — pinning a host style/profile, applying sandbox/permission policy, or running the same configuration in CI that the MCPJam Inspector uses for its Playground — start from a Host spec instead:
HostRuntime (returned by host.withManager(...)) snapshots the live Host on every .run(), so mutating the bound host between iterations takes effect on the next iteration. HostRunner snapshots once at construction. Pick HostRunner for a static spec, HostRuntime when you want the spec editable across calls. Personal computer. A Host can declare a personal cloud workstation via the computer property (type HostComputer, exported from @mcpjam/sdk). When set, the chatbox surfaces a bash tool and a web terminal for signed-in members. Use setComputer() to attach or detach it fluently:
Or pass it directly in the constructor:
null and an absent computer field hash identically, so existing host configs are unaffected. The computer field is automatically stripped from eval wire configs — evals never target personal computers. Statelessness. HostRuntime.run() does NOT auto-replay history across turns. Use PromptOptions.context to thread context explicitly:
Eval reporting (Stage 5). When you upload results to MCPJam and the reporter can resolve a host snapshot, it sends the canonical host config alongside the run ({ hostConfig, hostConfigHash }) so the persisted row in the Evals UI shows the exact host you ran with — the v1 ingest surface always accepts the pair. The snapshot comes from executor.getHostSnapshot?.(), falling back to MCPJamReportingConfig.host; result-only uploads with neither source omit the pair. Uploaded results don’t yet carry a per-iteration hostSnapshot field, so the pair stays run-level for now.

Generate evals from the Inspector

You can also generate eval code from the MCPJam Inspector. Click ⋮ → Copy markdown for evals on any server card, then paste it into an LLM. See the Quickstart for details.

Next Steps

Testing Across Providers

Compare performance across LLMs

EvalTest Reference

Full EvalTest API

EvalSuite Reference

Full EvalSuite API

Save Results to MCPJam

Auto-save, manual APIs, CI metadata, and artifact upload