plimsoll trainer · 06 / discoverable contract

Discoverable tools

A model calling your run_code tool, offered to it over MCP (Model Context Protocol, the standard an AI application uses to offer tools to a model), has to know what the tool returns and what the functions injected into the sandbox (its typed globals) accept. If the only source is a name, it probes blind. The fix is one document that produces every view of the contract, and a test that fails the moment a real return stops matching it.

One operation, three views

getLight(id) from the specgen example, as its three audiences see it: the model reads the tool definition, the sandbox code calls the typed globals, and the broker, the part of plimsoll that makes the sandbox's API calls, enforces the route list. plimsoll-specgen generates all three from the same OpenAPI document (a machine-readable description of an HTTP API), so they agree by construction. Flip the switch to change the API underneath them and watch which views go stale, and which check would catch it.

Mark each tool honestly

Tool annotations are four hints in an MCP tool definition that tell a client how a call behaves before it runs it: read-only, idempotent (calling it twice has the same effect as calling it once), destructive, and open-world (it can reach things outside your own backend). A wrong hint is worse than none: a tool that changes state but is marked read-only invites unconfirmed calls. Fill in the four hints for four tools, then check.

An output schema from real returns

Derive the result shape from what the tool actually returned, not from what you assume. A field is required only when every sample has it; an absent field is unknown, not a default. Toggle a field in a sample and watch the schema follow.

Serve the typed globals at runtime

The typed globals are not MCP tools, so they get no schema for free. A model needs their signatures before it writes sandbox code. Pick the delivery by what your server already registers, and keep one generated source.

An MCP resource

A resource is data an MCP server offers at a URI for the client to read. Here, a URI such as stockroom://sandbox-api.d.ts that returns the generated .d.ts, a TypeScript declaration file (or the same facts as JSON). Best when the server already registers resources: the client discovers the globals the way it discovers everything else.

A describe tool

describe_sandbox_api returning, per function, the typed parameters, the return schema, a one-line description and an example. For servers with no resource surface yet.

Not both. A resource and a tool that can disagree are two sources of truth, and they will drift. Whichever you pick, it is rendered from the same document as the tool schema and the route list.

The drift gate

A plausible-looking schema is not a correct one, and a correct one drifts: the API changes and the description does not. Confirm the definitions against the current protocol specification once, then test every declared shape against real returns on every build.

Keep reading