DEV Community

Alex
Alex

Posted on

An MCP tool set can gain a digest without changing

A server can advertise the same tools on two days and receive different answers from a measurement system: first, no tool-set digest; later, a digest.

The server does not have to change. The rules used to measure it can change.

That happened in HISTOR, our log of MCP tool definitions. It exposed a gap in our records: we could preserve an old "not digestible" result without saying which revision of the rules had produced it.

On November 6, we deployed MTL/1.2 to record that revision and explain why a tool-set digest is absent. MTL is our draft profile for labeling MCP observations, rather than a standard of the MCP project.

The fraction that changed the result

HISTOR reads the definitions an MCP server advertises: tool names, descriptions, and schemas. Its MTL profile defines a canonical representation from which it computes a digest.

Version 1.0 was restrictive about numbers. A schema containing a fraction, an exponent, or an integer beyond the safe integer range could leave the whole tool set without a digest. An ordinary schema default such as 0.5 was enough.

On October 31, revision 1.1 changed that handling. It reads numbers as IEEE 754 doubles and serializes them using the RFC 8785 canonical form. It also handles empty tool sets and repeated tool names.

Consequently, declarations that 1.0 declined could receive a digest under 1.1 without their authors editing anything. This was a change in our measuring rules, not evidence that those servers had repaired a problem.

The descriptor's mtl identifier remained "1". Digests already produced under 1.0 stayed unchanged. But an old label without a tool-set digest did not name the revision responsible for that result.

That missing context mattered when someone read the record later.

Two reasons for an absent tool-set digest

In the Agent Control Standard discussion, avp9-nexus proposed distinguishing a declaration nobody observed from one that was read but declined by a canonicalization profile, with the reason and profile identifier recorded. Our follow-up also records the profile revision.

For HISTOR, those situations need different records:

Reason What happened What the reader needs next
not_observed No tool set was read for the observation being described The read or access problem
not_digestible A tool set was read, but the profile revision declined to digest it The refusal code and the applicable rules

An empty list that was successfully read is an observation. Since revision 1.1, the empty set can have a digest too.

Neither absence reason says that a server is safe or unsafe. A signed label can still exist when the tool-set digest is missing; the missing field does not mean that every hash or signature is absent.

Revision 1.2 records the distinction using a closed set of reason values. A read tool set without a digest carries toolSet.noDigest, with a reason and the relevant profile code when known. Every new label also names profileRevision: "1.2.0".

Revision 1.2 changes no digest calculation. It makes the calculation's limits and revision part of the record.

Old records keep their uncertainty

During the November 6 rollout, a server-detail response contained this historical reason object:

{
  "reason": "not_digestible",
  "code": "MTL-NUM-001",
  "profileRevision": null,
  "decidedAt": "2026-10-20T21:55:11Z"
}
Enter fullscreen mode Exit fullscreen mode

The null is useful. That old label did not state its profile revision. The API reports the absence instead of filling in a revision based on what the newest software knows. The decision time belongs to the historical observation, not to the upgrade that made it easier to inspect.

New labels carry the revision explicitly. A reader of an old label may have other historical evidence, such as a deployment time, but the label itself should not acquire information it never contained.

Continuity records need the same care. They compare an earlier observation with a later one, so a missing digest must belong to the appropriate side.

A failed current read can carry not_observed under noDigest.current. A prior tool set declined by the profile has its reason on the prior side. If that earlier label named its revision, the continuity record copies it. If it did not, the revision remains absent.

An upgraded issuer does not silently relabel an old decision as its own.

Unchanged packages need another chance

Recording the revision also changes scheduling.

A package may already have been run at its current published version. If that run produced an undigestible tool set, a scheduler based only on package-version changes has no reason to try again. The package has not changed, but the observer's rules have.

HISTOR now makes such packages eligible for another run when the recorded MTL revision differs from the current one. The new run records the revision that judged its tool set.

If the current revision still declines the set, that decision is settled until relevant inputs change. The crawler does not repeat the same refusal indefinitely.

The scheduler's revision marker is measurement metadata. It is excluded from security events; upgrading the observer should not appear as a security event attributed to the package.

What we verified

The tests cover the two absence reasons, refusal codes, signature verification with the new fields, and continuity records whose earlier labels contain no revision.

A scheduler regression covers the unchanged-version case: a set declined under older rules runs again, then settles after judgment under the current revision.

Before switching production, a disposable HISTOR instance checked label generation and the list and detail APIs without network access. The November 6 deployment was then checked externally.

The public API exposes the distinction through its unobserved filter and undigested filter. Both returned the corresponding noDigest.reason in a fresh check on November 7.

A digest remains a commitment to a defined representation of advertised tools. It does not certify implementation behavior, source code, or safety. A signature makes the issuer's assertion attributable; it does not by itself prove that a retrieval occurred or when.

When HISTOR has no tool-set digest, the record can now say whether anything was read, why the rules declined it, and which revision made that decision.

We build HISTOR. This article was drafted with AI assistance using our profile specification, implementation, regression tests, and recorded rollout checks.

Top comments (0)