creating-mcp-agent-evals
Installation
SKILL.md
Creating MCP agent evals for an MCP tool family
Overview
Build a small, calibrated Langfuse eval suite for one tool family (tasks, storage, runs, …), then use its failures to fix the tools. Core principle: evals are designed from user intent, never from tool descriptions — the eval defines what should work; descriptions get fixed afterward to make naive agents pass it.
Commands, item shapes, probe patterns, and sweep queries: reference.md.
The flow
- Inventory the tools — every tool and every argument group needs at least one case (the coverage matrix at the end proves it).
- Probe the platform first. Before writing any case that depends on API behavior (required fields, uniqueness rules, limits, error messages), verify it with a throwaway
tsxscript against the real API. Never write a case on an assumed contract — that's how you get input values the schema rejects. - Two datasets, one per CI gate.
mcp-server-evals-pr(the--datasetdefault) holds thekind: "tool-call"items and gates PRs (PR open/reopen, or thevalidatedlabel);mcp-server-evals-mergeholds thekind: "agent"items and runs on push to master. Every item declaresmetadata.kind("tool-call", single-turn, only the first tool call is asserted, no judge, nothing executes, or"agent", multi-turn, run to completion and scored by an LLM judge). Akind: "tool-call"case setsexpectedTools(required) and, to pin arguments (not just the tool name),expectedArgs— a flat object, every listed key must deep-equal the captured call's same key, unlisted keys ignored; addmcpToolsOnly: truewhen a case must isolate MCP-vs-MCP tool choice from Claude Code's built-ins. Akind: "agent"case that provokes an error on purpose (a collision, a not-found, requirement discovery) setsmetadata.expectedErrorsto the tool name(s) allowed to fail on it — the zero-tool-error gate exempts only those, so it never masks an unrelated failure the way a blanket error-tolerant dataset would. Give the item id the dataset-prefixed shape —pr/<tool>/<slug>in the pr dataset,merge/<family>/<slug>in the merge one, where the middle segment is the tool or tool family (search-actors,tasks,web-fetch, …) and<slug>is the rest. - Write cases in waves: 2–3 easy (single tool, explicit input) → 1–2 medium (cross-tool chains, run options) → 2–3 hard (vague user language, error recovery, collisions). Run and review each wave before writing the next.
- Calibrate on the strongest model first (Opus). A failure there is a case defect or a product gap — never a description problem. Only a calibrated suite (strong model 100%) can attribute weaker-model failures to descriptions.
- Ladder down (Sonnet → Haiku). Passes-on-Opus-fails-on-Haiku = the tool description or output doesn't carry a naive agent. That's the signal you built the suite for.
- Fix tools via outputs before descriptions. A steering sentence in the tool's response summary/nextStep reaches every agent on every call; description text gets skimmed. Both output nudges that fixed Haiku failures in the original build were response-text changes.