expectedToolCalls and never had them checked can start failing. That is the bug being fixed — the same run was already failing in the MCPJam dashboard, which recomputed the match server-side.
Why this changed
Before 3.0,expectedToolCalls was upload metadata. The local verdict came from your test function alone; the platform then re-derived the tool-call match from the case snapshot. The two could disagree, and when they did the SDK was the one telling you what you wanted to hear:
Breaking changes
expectedToolCalls is enforced locally
If a test declares expected tool calls, they are matched during the run and a mismatch fails the iteration.
The expectation was wrong or stale
The expectation was wrong or stale
Fix or delete it. The tool may have been renamed, or the agent legitimately solves the task another way now.
The expectation was over-specified
The expectation was over-specified
Relax the matcher rather than the assertion:
It was only ever documentation
It was only ever documentation
Remove
expectedToolCalls. A test with no expectations behaves exactly as it did in 2.x — your test function is the whole verdict.Tests that declare neither
expectedToolCalls nor predicates are unaffected by this release.precision() and recall() return real values
In 2.x, precision(), recall() and truePositiveRate() all did return this.accuracy() — three names for the pass rate. They now compute genuine micro-averaged values from the tool-call matches, and throw when no test in the run declared expectedToolCalls, because there is nothing to compute them from.
precision() as a stand-in for accuracy, call accuracy() directly.
falsePositiveRate() is deprecated
It returned failures / iterations — the failure rate, not a false-positive rate. Use unexpectedToolCallRate(), the fraction of expectation-bearing iterations that made a call nobody asked for. falsePositiveRate() still returns the legacy value for runs without expectations, so existing dashboards do not move.
New in 3.0
Predicates work code-first
The deterministic check engine was hosted-only. It now runs in your test file, gating the iteration and reporting the same verdicts, so the dashboard’s check chips and cross-run criterion trends light up for code-first runs.failOnToolError. See the predicate gate for the full list of types.
matchOptions
How expectedToolCalls is matched, layered suite → case and validated when the test is constructed:
EvalTest reference.
Upgrade checklist
1
Bump the package
2
Run your suite
Failures here are expectations that were never being checked. Work through them with the three options above.
3
Replace deprecated metric calls
falsePositiveRate() → unexpectedToolCallRate(). If you read precision() or recall() expecting the pass rate, switch to accuracy().4
Optional: adopt predicates
Anything your
test function asserts about the transcript — a tool was called, the reply contains a phrase, no tool errored — is expressible as a predicate, which makes it visible in the dashboard instead of hidden inside a boolean.Unchanged
Connecting to servers,HostRunner / HostRuntime, prompt execution and multi-turn context threading, reporting configuration, and the run URL printed after an upload all behave as they did in 2.x.
