Running evals & description workflow

June 24, 2026 · View on GitHub

End-to-end flow

The main loop measures live MCP tool descriptions, improves wording locally, then promotes changes back to the MCP server.

setup_test_data.py  →  run_evals.py (baseline)

              results/runs/<run_id>/summary.{md,json}
              results/latest.json  ← pointer to latest run

              suggest_overrides.py

              results/runs/<run_id>/suggested_overrides.json

              suggest_overrides.py --apply

              description_overrides.json

              run_evals.py --with-description-overrides

              promote to MCP server  →  run_evals.py (baseline again)
StepCommand / filePurpose
1. Preparesetup_test_data.py, MCP server runningEval tables + live tools
2. Baselinerun_evals.pyAgent sees live MCP descriptions; writes artifacts under results/runs/<run_id>/
3. Triageresults/latest_summary.md or run directoryPass/fail counts, eval prompts, recommendations
4. Draft fixessuggest_overrides.pyBedrock drafts revised descriptions for failed ambiguous_selection cases
5. Reviewrun's suggested_overrides.jsonHuman review — not applied automatically
6. Applyuv run python suggest_overrides.py --applyReplace description_overrides.json with draft suggestions only
6. Test locallydescription_overrides.json + --with-description-overridesPatch descriptions without changing the MCP server
7. ShipEdit descriptions in MCP server repoRe-run baseline evals to confirm

Running evals

Before a live run: test tables created, MCP server at MCP_SERVER_URL. run_evals.py runs preflight automatically.

python run_evals.py                              # all modules
python run_evals.py --module base                # one module
python run_evals.py --module base --type ambiguous_selection
python run_evals.py --verbose
python run_evals.py --run-label after-tablelist-fix   # optional label in run directory name
python run_evals.py --list-runs                       # show recent runs

--type filter

ValueMatches case IDs containing
happy_pathhappy
ambiguous_selectionambiguous
missing_parametermissing
multi_toolmulti_tool
multi_turnclarify_then_call

Advanced filtering via deepeval/pytest, e.g. deepeval test run tests/ -k "test_base and tablePreview".

Baseline vs overrides

Default: evals use live MCP server tool descriptions.

Opt-in overrides: review the draft, then apply with suggest_overrides.py --apply, or re-run with:

python run_evals.py --module base --with-description-overrides
python run_evals.py --module base --description-overrides-file my_overrides.json

Or set USE_DESCRIPTION_OVERRIDES=1 / DESCRIPTION_OVERRIDES_FILE=... in .env.

Suggesting override drafts

After a baseline run with failures:

uv run python suggest_overrides.py
uv run python suggest_overrides.py --type missing_parameter
uv run python suggest_overrides.py --type ambiguous_selection,happy_path

Processes failed ambiguous_selection, happy_path, missing_parameter, and multi_tool cases by default. Each type gets a tailored prompt:

Case typeWhat it revises
ambiguous_selectionBoth competing tools — sharpen routing boundaries
happy_pathExpected tool (and wrong tool if one was called)
missing_parameterTools called prematurely — add “ask first” constraints
multi_toolTools in the workflow — clarify sequencing

missing_parameter cases where the agent never called a tool (judge-only clarification failure) are skipped — those are agent behavior, not description routing.

Flags: --summary, --output, --overrides-file, --type, --dry-run.

Reads the latest run summary (results/latest.jsonresults/runs/<run_id>/summary.json), fetches live MCP descriptions, and writes the draft into that run directory (also copied to results/suggested_overrides.json). Review the draft, then apply:

uv run python suggest_overrides.py --apply
uv run python suggest_overrides.py --apply --dry-run          # preview merge
uv run python suggest_overrides.py --apply --tools base_tableList  # one tool only
uv run python run_evals.py --with-description-overrides

Results layout

Each eval run gets its own directory under results/runs/. The directory name encodes when and how the run was executed, for example:

2026-06-23T20-40-34.611558Z__base__overrides

Format: <timestamp>__<module>__<baseline|overrides>[__<case-type>][__<run-label>]

PathContents
results/runs/<run_id>/summary.mdHuman-readable triage report for that run
results/runs/<run_id>/summary.jsonStructured case results
results/runs/<run_id>/manifest.jsonRun metadata and artifact list
results/runs/<run_id>/suggested_overrides.jsonLLM draft from that run's failures (when generated)
results/latest.jsonPointer to the most recent run
results/index.jsonNewest-first list of recent runs with pass/fail counts
results/latest_summary.mdCopy of the latest run summary (backward compatible)
results/latest_summary.jsonCopy of the latest run JSON (backward compatible)
results/suggested_overrides.jsonCopy of the latest suggestion draft (backward compatible)

List recent runs:

uv run python run_evals.py --list-runs

Other files may appear under results/ from optional tooling (audit logs, live description dumps, etc.) — those are not tied to a specific eval run.