A tool optimization is a stored experiment
A tool optimization finds the tool metadata (names, descriptions, input schema text) that makes a client call the right tools more often. runToolOptimization already runs one: a baseline, candidate variants round by round, a regression guard, a paired sign-flip test corrected for the number of variants tried, and a recommendation. The optimize-mcp-tool-metadata skill says how to write candidates.
Using it on a real server showed what is missing.
- The loop is one function call. The candidates come from a
proposeVariantscallback inside one process. An agent that wants to read the results and write the next candidates has to write a script that calls the model itself. Nothing on the command line runs an optimization. - Nothing is kept between rounds. A round on a desktop client takes hours. If the process stops, the optimization is lost, though every round's run is on disk. Rebuilding the result from those runs took a patched build.
- The server can change during an optimization. A hosted server's tool descriptions change when it deploys. A round measured against new descriptions is compared with a baseline measured against old ones, and nothing notices.
- The winner's gain is overstated. The winner is the best of several noisy measurements, so its measured gain is biased upward, even when the corrected test says it is better. The fix is a fresh run of the baseline and the winner, and that is also how a change found on a cheap client is checked on the client that matters.
- Smaller gaps. Nothing limits how many variants a run tries. An eval's optimization can't run in an environment (
envis not passed on). On an eval, nothing reads the server's current metadata, so a proposer or a report can't show what a candidate changed.
Decision
- An optimization is a record on disk, and the runs it made.
<eval dir>/optimizations/<id>/optimization.json(mst.optimization/v1) holds the setup and the history: the eval config and base variant, the tools candidates may change, the metric, the case-grouping rules, the variant budget, the baseline's run (which holds the servers' tool metadata), and each round's candidates with the run that measured them. Each round is an ordinary run (mst.run/v1) in the eval'sruns/, marked with the optimization's id and its role, and never the eval's latest run, somst runkeeps comparing with the last ordinary run. Scores are not stored. They are computed again from the runs whenever the record is opened, so stored results never disagree with the runs, and reopening an optimization replays it. - It advances in steps, and anyone can take them.
startruns the baseline and reads the servers' tools, stores the record, and then runs a grouping run when no case is taggedregression. A grouping run that doesn't finish runs before the next round.evidenceshows what a proposer may see: the editable tools' current metadata, the other tools' descriptions, each case's expectation and result, the calls of failed trials, and every earlier candidate with its change from the baseline. Held-out cases, tool responses and final answers are left out.tryruns a set of candidates as one round.finishjudges every candidate against the number tried and writes the recommendation.- An agent, a person or MST's own proposer takes these steps.
runToolOptimizationtakes them in one call, and still accepts aproposeVariantscallback.
- MST checks every candidate before it runs. A candidate may change only the tools the optimization lists as editable, and only their name, their description, and the
descriptionandtitletext inside their input schema. A change to a parameter name, a type, an enum,requiredor the schema's structure is refused, because the server would reject the calls and the round would measure that. Renames follow the tool-surface rules (valid names, no collisions). A round that would go over the variant budget (maxVariants;mst optimizedefaults to 6) is refused before it runs. - Every run records the tools its servers served. When the optimization asks,
runEvallists the base variant's servers' tools once, before any client starts, and keeps them in the run. A round whose servers serve different metadata from the baseline's fails, and says to start a new optimization. So does a round that differs from the baseline in anything else it measures with: its datasets' content hashes, the eval config's judges and their options, or the base variant's client, model and options. Both checks run before any client starts (runEval'sexpectedServedToolsandbeforeCollect), so a refused round costs nothing. - An optimization's runs are never resumed. Resumed trials would run against whatever the servers serve then, unchecked. A round whose run is missing trials stays to run, and runs again in full. A baseline with missing trials fails
start. - One process steps an optimization at a time.
try,--retryandfinishhold alockfile in the optimization's directory, and refuse a record that another process changed after this one read it. A lock left by a process on the same machine that no longer runs is taken over. - A run is kept once it is stored complete. When
runEvalstores a complete run and then fails (a result store that rejects the upload, say), the step keeps that run instead of collecting it again. - Confirmation is a fresh run.
finish --confirmruns the base variant and the winner again, on every case including the held-out ones, optionally on another eval config with the same servers (a desktop client, for example). The confirmation is one comparison, so it is tested at 0.025 with no correction. With--confirm, MST recommendsapplyonly when both the optimization and the confirmation show a clear improvement and no broken cases. - MST's proposer is a built-in step, not an extension kind.
proposebuilds the same evidence, asks a model throughcreateJudgeCompletion(any judge provider, gateways included) for at most the budget left, checks the reply, and runs it as a round. With--out, it only writes the candidates, for an agent or a person to edit andtry. Aproposerextension kind can come once a second proposer exists. - Rounds run where runs run. The optimization passes
envand its options to every run, so rounds can collect in Docker. - Out of scope. Applying the winner to the server or the eval config. Changing the dataset, the servers or the tools' behavior. Pairwise judges during rounds. Optimizing several base variants at once (use
--confirmon another config). Detaching an optimization's coordinator.
Consequences
- An agent drives an optimization with
mst optimize start,evidence,tryandfinish, and needs no script. The skill describes this loop. - A stopped optimization continues with the next command. A round whose run never finished or is missing trials runs again with
try --retry. Running a partial round in full costs more than resuming it, but every trial of a round then ran against the tools that were checked. start,evidence,tryandfinishship first.finish --confirmandproposefollow, on the same record.runToolOptimizationon an eval writes a record too. On a dataset, inside a Playwright test, it runs in memory as before.- The tool metrics (
toolF1,toolPrecision,toolRecall) stay dataset metrics. On an eval,passRateover cases that assert onlytoolsTriggeredis the trigger rate. - The record is a new file format, versioned like
mst.run/v1: readers ignore fields they don't know.