MCP Tool Pinning: A Compatibility Guide
In a production environment, an MCP tool schema breaking change narrows the set of valid calls, meaning a prompt that worked yesterday suddenly fails today. Conversely, a backward-compatible change just expands the options. A simple byte pin can't tell the difference. To solve this, I've been using compat_gate.py to diff the inputSchema and replay recorded agent calls—it stays silent on compatible updates and fails-closed on breaking ones.
Why manifest pinning triggers on every update
The pin operates on a canonical SHA-256 of the name + description + inputSchema. While it's smart enough to ignore JSON whitespace or key ordering, it's paranoid about meaning.
The reality of the MCP spec is that revisions happen constantly. Servers update, descriptions are tweaked to help the LLM understand the tool better, and versions shift. Every single one of these events flips the pin's bit. We've realized that tracking change isn't the same as controlling compatibility. A changed contract isn't necessarily a broken one.
Defining "Breaking" in Tool Schemas
This comes down to basic subtyping. A schema defines a set of valid argument objects.
- Backward-compatible: The new set contains the old one. Every call that validated before still validates now.
- Breaking: The new set is smaller. Some previously valid calls now fail.
If you're building a real-world LLM agent deployment, you can't rely on a hash alone. You need a compatibility check that understands the schema logic, not just the bytes. This allows the team to accept harmless updates (like better descriptions) without manually resetting pins every time a vendor pushes a minor patch.