Generated from cat-harness/skills/folio-core/mcp-assembly.md — do not edit here.

✎ Edit this page’s source

MCP assembly — many Tools, one service, one namespace

mcp-projection maps one Tool node to one MCP tool. This is what happens when there are several, which is the normal case and where the problems are: a flat namespace shared by tools from an instance, its dependencies, and whatever else the agent has mounted.

Naming — the model reads these, so they are an interface

An MCP tool name is what a model pattern-matches against when deciding what to call. It is not an identifier that merely has to be unique.

<subject>_<verb>, lower snake case. bean_claim, bean_list, folio_render. Subject first, because an agent scanning tools/list is looking for the thing before the action, and because it groups related tools adjacently in a flat list with no grouping mechanism.

  • Verbs are from a closed set, and a new one needs a reason: list, get, create, update, delete, run, check, sync. bean_fetch beside folio_get costs a model a guess on every call.
  • Never encode the transport, the vendor or the binary. github_pr_create names a forge in a name a skill is supposed to reach generically; the neutral pr_create with per-forge Tool nodes behind it is the shape skills-and-tools asks for.
  • Never version in the name. bean_claim_v2 beside bean_claim asks the model to choose, and it will sometimes choose wrong. See versioning below.

Collisions are refused, not resolved

Two Tool nodes projecting to one name is an error at assembly time, not something to paper over by prefixing the loser.

This is the same rule ContributionRegistry and GraphTypologyRegistry already follow, for the same reason: automatic disambiguation means the name a caller gets depends on load order, and load order is not something anybody reasons about. Refuse, name both contributors, and make somebody choose.

One exception, and it is the diamond case: the identical Tool node reached twice through a dependency graph is a no-op, not a collision. Identical means same id, same io, same invoke — not merely the same name.

Prefixing across instances

An instance inherits its dependencies’ Tool nodes the same way it inherits their skills. When two different instances contribute a tool of the same name, the collision rule above applies — but the fix is a declared prefix on the contributing instance, not an ad-hoc rename at the consumer:

fa_bean_claim        # folio-assistant's
qou_bean_claim       # the folio's, if it genuinely has its own

A prefix belongs to the instance and is written down once, so the same tool has the same name everywhere it appears. A consumer that renames what it imports produces a namespace nobody else’s documentation matches.

Versioning

The service is versioned; the tool name is not. A breaking change to a tool’s schema is a version bump on the server, announced in its metadata, not a second tool beside the first.

When both must run at once — a migration window — run two servers, not one server with two generations of tool. The agent’s mount configuration then says which it is talking to, which is a place a human can look, rather than the model choosing from a list where both look plausible.

Grouping, given MCP has none

MCP’s tool list is flat: there is no namespace, no category, no folder. The kg/ grouping this harness uses for skills has no counterpart in the protocol.

So the grouping has to survive in two places instead. The name carries it via the subject-first rule — bean_* sort together and read as a family. The description carries the rest: the first clause of tools[].description should make the subject unambiguous without the name, because a model that has truncated or reordered the list is reading descriptions.

Do not attempt to recreate grouping with separators (bean/claim, bean.claim). Clients render names literally and some validate them against a restricted character set; a clever separator is a portability bug for a cosmetic gain.


folio-assistant — code under the Apache License 2.0, documentation under CC BY 3.0. Generated schema and API references are rebuilt from source on every push to main.

deployed b08c961 · 2026-10-23T23:11:09Z