Step 1 of 4
Separate logic from protocol glue
Testability is an architecture property - create it first.
Refactor for testability. Split each tool into: a pure(ish) handler function (typed inputs in, result or typed error out - no protocol objects) and a thin MCP registration wrapper (schema binding, content conversion, error mapping). The handler must be importable and callable in tests without any transport. Verify by writing one smoke unit test per handler calling it directly. This refactor should not change observable behavior - re-run the existing manual checks after.
Expected after this step
Handlers callable directly in tests, wrappers reduced to glue.
Should not happen
- ✕Testing handlers only, missing serialization and protocol bugs entirely
- ✕No contract pinning, so tool renames silently break every downstream host
- ✕Bugs fixed without regression tests, returning two releases later
- ✕A suite that exists but does not run automatically
Verify before continuing
Do not move on until every check is true. The complete button stays locked until then.
Do not continue if…
- !Testing handlers only, missing serialization and protocol bugs entirely
- !No contract pinning, so tool renames silently break every downstream host
- !Bugs fixed without regression tests, returning two releases later
- !A suite that exists but does not run automatically
If the AI messes this up
Use this when the AI fakes progress or breaks the feature. It forces a real fix.
Handlers are entangled with server context. Inject dependencies (config, clients) as parameters or a context object constructed in tests - global server state is the testability killer.