Keep MCP tools under stable server-qualified provider names
MCP names used positional aliases, so adding a default tool changed the model-facing identity. Canonical names now produce stable, reversible wire aliases; mcp.docs.search becomes mcp__docs__search. Hooks, tool admission and approvals continue to use the canonical name.
Design
One tool-name table handles declaration, controls, native stream decoding and reverse lookup across Responses, Chat, Anthropic and Gemini. Overlong or colliding aliases use a stable digest and salted collision resolution. Exact alias capacity remains under native custody.
Native generation and token counting share Names::funded. It charges each digest's domain, salt and canonical bytes before hashing, including every collision retry. The wire index is sorted again only when collision resolution changes a binding.
Deletions
Removed positional aliases and the unconditional second wire-index sort. Replaced the arithmetic-only sort control with a mutation of the actual production sort. Relative to the recorded main base: +1,162 / -79, net +1,083 lines, predominantly regression proofs and HTTP fixtures.
Decisions
- Canonical tool names remain the authority and history keys. Aliases exist only at the provider wire boundary.
- Both stock tool execution and direct-tool dispatch construct approvals through
tool_approval_requestand its action binding. Hook pre/post matching receives the restored canonical name before policy or approval evaluation. - Consumer tests use the real HTTP adapters, hook matcher and approval constructor. They exercise the shared identity boundary used by manual, policy, LLM and parent-agent approval consumers rather than copying those consumers.
Guarantee
- Class: K/L (codec identity and disconnected consumers), H/F (unfunded work and retained allocation). A private reversible table owns the canonical-to-wire mapping. One funded builder admits every native digest before execution; unchanged bindings cannot reach the final sort.
- Proof: shrinking properties cover reversible, collision-free, order-independent mappings, exact allocation capacity, hash-byte admission including salt retries, and the actual sort/comparison counters. Production mutations skip hash admission and restore the redundant sort; the same oracles reject both. Real HTTP tests for all four adapters feed restored calls into pre/post hook matching and the common approval action binding. Production mutations substitute the wire name in each consumer; both fail the canonical identity oracle. Existing checked-in alias fuzz corpus and round-trip oracle remain covered; the grammar and decoder are unchanged by these review fixes.
- Entry points: tool declarations and named controls; portable/native adapter generation and restored call batches; native token counting; pre/post hooks; stock and direct-tool approval request construction. Adapter scenarios retain canonical tool execution/result round trips and insertion of an earlier-sorting default tool.
- Gaps: none.
Tests
At signed head 04ae436c19cd618194d043ca7029aaa004cd2d2f, through bs.ps1 (job 1792320623931-1250396):
- Tool-name properties, exact accounting and production negative controls: 20 passed, 0.044 s.
- Canonical hook/approval HTTP tests and production negative controls: 3 passed, 0.031 s.
- Provider scenario runner (
E2E_FILTER=providers/): passed, 1.909 s, including fixture validation. - Windows GNU Harness and Providers
--lib --tests: passed, 6m08s.
Exact focused gate: Q:/lanes/co-features-982-review-gate.sh, submitted from Q:/wt/context-c-mcp through Q:/lanes/bs.ps1 bash -c. Linux test build 6m56s. One feature closure: acyclic-harness/filesystem-local,acyclic-harness/native-execution,acyclic-harness/terminal,acyclic-harness/mcp-http,acyclic-harness/test-support,acyclic-harness/grpc. Stable toolchain 1.98.1; tests rerun from the built binaries.
The initial build failed with ENOSPC during bb2's reported disk incident; it produced no test result. This run is the single authorized infrastructure retry.
The provider/consumer integration tier would have caught the live failure earlier. Earlier tests checked aliases and echo execution without checking canonical hook selection or approval action hashes; both are now explicit independent oracles.