Skip to content

feat(trg): support fixed mcp mocks with expectation guards - #153

Merged
yordis merged 8 commits into
mainfrom
yordis/feat-eval-mcp-mocks
Sep 14, 2026
Merged

yordis merged 8 commits into
mainfrom
yordis/feat-eval-mcp-mocks

Conversation

@yordis

@yordis yordis commented Sep 13, 2026

Copy link
Copy Markdown
Member
  • An eval that exercises a skill's use of an mcp server had no way to run without the real server, which made those cases either untestable or dependent on a live external dependency.
  • Fixed responses alone would let a skill pass while calling the wrong tool or calling nothing at all, so the mock carries expectations about what must be called and fails the run when they are not met.

Stacked on #147.

Summary by CodeRabbit

  • New Features
    • Added fixed MCP mock support for skill evaluations, including tool responses, input and file substitutions, overrides, and expectation validation.
    • MCP calls are recorded with accessible call logs and violation details.
    • Claude evaluations can use MCP configuration with strict configuration enforcement.
  • Bug Fixes
    • Mock expectation mismatches now appear as failing evaluation assertions.
    • Evaluation retries and cached runs preserve the correct mock-call artifacts and results.
  • Documentation
    • Added reference documentation covering MCP mock declarations, behavior, artifacts, and runner support.

A harness offering a control and trg exercising it were folded into one
value, so a reader of the support table could not tell which cells describe
trg's actual invocations from which just describe the harness's --help. The
same collapse let an argument builder ask any cell for a flag, so a control
could sit in the table looking wired up while no runner ever read it.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Real mcp servers make eval runs nondeterministic and unsafe to replay
in ci, so fixed mocks let cases assert on tool inputs without a live
server. A runner that cannot honor --strict-mcp-config must skip a
mocked case rather than silently run it against whatever mcp servers
happen to be configured on the host.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@cursor

cursor Bot commented Sep 13, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches eval run orchestration, harness argv, caching, and grading for a new MCP mock path; mistakes could skip runs incorrectly or let cache hits hide mock violations (explicitly tested against).

Overview
Adds fixed MCP mocks for skill eval cases so runs can stub tool responses without a live MCP server, wired end-to-end through run, cache, reports, and grading.

Eval suites declare mocks as frontmatter markdown under evals/mocks/ (with per-case overrides). At run time trg resolves and hashes the mock set, materializes JSON plus an --mcp-config that spawns a hidden mock-server stdio MCP process, and logs every mocked call to mock-calls.jsonl. Optional expect constraints on call inputs are checked but do not block the mock response; mismatches land on mock_violations and become ordinary failing assertions during grading. Claude Code now drives MCP via --mcp-config together with --strict-mcp-config; runners without MCP support skip mocked cases as unsupported rather than running them.

Cache keys gain optional mock_hash, reuse copies mock-calls.jsonl, and retry attempts clear stale mock logs so discarded attempts cannot fail the surviving run. Docs and report.json schema document the mock format, artifacts, and harness table changes.

Reviewed by Cursor Bugbot for commit 274d77e. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: da92c2fd-e1aa-4b84-88cc-faba232453b0

📥 Commits

Reviewing files that changed from the base of the PR and between 0aa029c and 274d77e.

📒 Files selected for processing (18)
  • crates/trg/docs/reference/ai-skills-eval.md
  • crates/trg/schemas/report.json.schema.json
  • crates/trg/src/agentskills/cache.rs
  • crates/trg/src/agentskills/case_directories.rs
  • crates/trg/src/agentskills/ci.rs
  • crates/trg/src/agentskills/grading.rs
  • crates/trg/src/agentskills/html_report.rs
  • crates/trg/src/agentskills/mocks.rs
  • crates/trg/src/agentskills/mod.rs
  • crates/trg/src/agentskills/report.rs
  • crates/trg/src/agentskills/runner/capabilities.rs
  • crates/trg/src/agentskills/runner/claude_code.rs
  • crates/trg/src/agentskills/runner/mod.rs
  • crates/trg/src/agentskills/runner/tests.rs
  • crates/trg/src/cli.rs
  • crates/trg/src/commands/ai/skills/eval/mock_server.rs
  • crates/trg/src/commands/ai/skills/eval/mod.rs
  • crates/trg/src/commands/ai/skills/eval/run.rs

📝 Walkthrough

Walkthrough

Changes

The evaluation harness now supports fixed MCP mocks with suite and case overrides, expectation checks, response substitutions, call logging, and a hidden stdio mock server. Runs pass materialized MCP configuration to supported runners, record violations, grade them as failures, and include mock content in cache identity.

MCP mock execution

Layer / File(s) Summary
Mock declarations and server protocol
crates/trg/src/agentskills/mocks.rs, crates/trg/src/commands/ai/skills/eval/mock_server.rs, crates/trg/src/commands/ai/skills/eval/mod.rs, crates/trg/src/cli.rs
Fixed mock files now support expectations, file and input substitutions, response bodies, errors, materialized MCP configuration, and JSON-RPC tool calls. The server records calls and violations.
Evaluation-run MCP integration
crates/trg/src/agentskills/runner/*, crates/trg/src/commands/ai/skills/eval/run.rs
Runs resolve mocks, skip unsupported runners, pass MCP configuration to Claude Code with --strict-mcp-config, clear logs between retries, and retain completed-attempt calls.
Violation reporting and cache behavior
crates/trg/src/agentskills/report.rs, crates/trg/src/agentskills/grading.rs, crates/trg/src/agentskills/cache.rs, crates/trg/schemas/report.json.schema.json, test fixtures
Run records and the report schema store mock violations. Grading emits failing assertions for violations. Cache keys include mock content, and cache hits copy mock logs and violations.
Documentation and discovery coverage
crates/trg/docs/reference/ai-skills-eval.md, crates/trg/src/agentskills/case_directories.rs
The reference documents mock declarations, artifacts, cache behavior, and guarded Claude Code MCP configuration. Directory discovery tests exclude evals/mocks from case discovery.

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant EvalCase
  participant EvalRun
  participant ClaudeCode
  participant MockServer
  participant RunRecord
  EvalRun->>EvalCase: resolve_mock_set
  EvalRun->>MockServer: materialize MCP config
  EvalRun->>ClaudeCode: invoke with MCP config and guard flag
  ClaudeCode->>MockServer: tools/call
  MockServer-->>EvalRun: response and call log
  EvalRun->>RunRecord: store artifacts and mock violations
Loading
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yordis/feat-eval-mcp-mocks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread crates/trg/src/agentskills/mocks.rs
Comment thread crates/trg/src/agentskills/cache.rs
an expectation that cannot survive the cache key's own serialization
means the guard never runs, so a violation is invisible from the
very first run. a cache hit that forgets what the source run found
turns a suite that already failed into one that reads as clean on
reuse.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread crates/trg/src/commands/ai/skills/eval/run.rs
A retried attempt is discarded whole, so the calls it made of the mocks have to go with it. Otherwise a run that did everything asked of it is failed for a call it never made.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread crates/trg/src/agentskills/mocks.rs
Comment thread crates/trg/src/commands/ai/skills/eval/run.rs
The harness resolves these paths from the workspace rather than from where the run was started, so a relative out-dir sent it looking in the wrong place and it would not start at all. Clearing the call log between attempts now empties it instead of removing it, because a run that called nothing still owes the reader an artifact saying so.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread crates/trg/src/agentskills/mocks.rs Outdated
A file reference was documented as resolving next to the mock that writes it and
resolved from the mocks root instead, so a payload placed where the docs say
could not be found at all and one name could only ever mean one file for the
whole suite.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread crates/trg/src/agentskills/mocks.rs
Comment thread crates/trg/src/agentskills/mocks.rs
A regex compiled at match time cannot be told apart from one that simply did
not match, so a typo in a mock's `expect` reads as a skill that called the
tool wrongly. The same function pinned every other path in the generated mcp
config to a root and left the command it spawns to whatever `current_exe`
happened to hand back, which the harness then resolves against the run's
workspace rather than where trg was invoked.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Base automatically changed from yordis/fix-eval-capability-matrix-honesty to main September 13, 2026 22:00
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

# Conflicts:
#	crates/trg/docs/reference/ai-skills-eval.md
#	crates/trg/schemas/report.json.schema.json
#	crates/trg/src/agentskills/cache.rs
#	crates/trg/src/agentskills/ci.rs
#	crates/trg/src/agentskills/grading.rs
#	crates/trg/src/agentskills/report.rs
#	crates/trg/src/agentskills/runner/capabilities.rs
#	crates/trg/src/agentskills/runner/claude_code.rs
#	crates/trg/src/agentskills/runner/mod.rs
#	crates/trg/src/commands/ai/skills/eval/mod.rs
#	crates/trg/src/commands/ai/skills/eval/run.rs
@yordis
yordis merged commit deba02c into main Sep 14, 2026
10 of 11 checks passed
@yordis
yordis deleted the yordis/feat-eval-mcp-mocks branch September 14, 2026 14:20

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 274d77e. Configure here.

eprintln!("Run {}: failed to resolve mcp mocks: {}", run.id, e);
run.status = "failed".to_string();
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mock load failures get graded

High Severity

A mock that fails to resolve or materialize sets status to failed with no failure_kind and returns before the workspace exists. started() only treats known not-started kinds as unexecuted, so grading still scores the run and reads missing outputs as assertion failures. An authoring error in a mock file then looks like the skill failed the case.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 274d77e. Configure here.

line.push('\n');
let mut file = fs::OpenOptions::new().create(true).append(true).open(path)?;
file.write_all(line.as_bytes())
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call log writes can interleave

Medium Severity

Every mocked server process appends to the same mock-calls.jsonl with no lock. Interleaved lines are dropped by read_mock_violations, which ignores parse failures. Concurrent tools/call traffic, especially with large inputs, can lose expect mismatches and let a run pass grading.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 274d77e. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant