From 65f69d96a930b0e66d21a387f4eb1253d4b66cb8 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 17 Oct 2026 13:35:12 +0200 Subject: [PATCH] Describe the mesh MCP server as it runs and mark its design implemented (issue 1008) mesh-console is gone: the tool runner (node-tools) is a core component on every node, host-side and never a container (ADR 0175), announcing seven tools by address (ADR 0195, 0367), not the five-tool container the old as-is doc described. The to-be document's unsettled items get owners: the mesh's own verbs already shipped (ADR 0154); identity and per-assignment grants are design 58 milestone 6 (issue 883). --- 03-DESIGN/00-as-is/13-the-console.md | 150 ++++++++++++++++++--------- 03-DESIGN/01-to-be/34-the-console.md | 23 ++-- 2 files changed, 118 insertions(+), 55 deletions(-) diff --git a/03-DESIGN/00-as-is/13-the-console.md b/03-DESIGN/00-as-is/13-the-console.md index d63d191e..44b19bf5 100644 --- a/03-DESIGN/00-as-is/13-the-console.md +++ b/03-DESIGN/00-as-is/13-the-console.md @@ -1,69 +1,125 @@ --- layer: as-is status: implemented -code: [mesh-catalog modules/mesh-console, mesh-tools src/mesh.ts, mesh-tools src/http.ts, mesh-tools src/runtime.ts, mesh-controller internal/broker, mesh-controller cmd/mesh-controller/check.go, mesh-controller cmd/mesh-controller/seatverbs.go] -updated: 2026-10-10 +code: [mesh-tools, mesh-host, mesh-controller] +updated: 2026-10-17 decisions: - "ADR 0152" - - "ADR 0095" - - "ADR 0037" + - "ADR 0175" + - "ADR 0195" + - "ADR 0197" + - "ADR 0367" - "ADR 0154" --- # The mesh MCP server, as it runs -**The mesh's tools reach a person through a module the mesh assigned to their machine.** Since -2026-09-30 a workstation that is a node can be assigned `mesh-console`; the mesh mints a bus account -`.mesh-console`, seals its credential to the machine, and the container binds -`127.0.0.1:` with the port the mesh assigned for the manifest's declared one. An agent on the -machine is pointed at `http://127.0.0.1:/mcp` and sees the mesh's tools; a person uses the same -endpoint. Nothing on the machine holds a credential a person had to carry. +**The `mesh-console` container no longer exists.** Read 2026-10-17 from `mesh-tools` (package +`node-tools`), `mesh-host` and `mesh-controller` on their forges' main, and from the live mesh +through `mesh_overview`, `mesh_machine`, `mesh_runtimes` and `mesh_describe`. Checked: the +catalogue (`mesh-catalog`) carries no module named `mesh-console` any more — the name survives only +in the glossary's retired-words list and in a test fixture — and none of the four nodes answers a +module of that name. + +## What it is now + +**The tool runner is one of the mesh's core components**, named `node-tools` beside +`mesh-controller`, `mesh-host` (the node-engine) and `nats` (the bus) — the mesh's own repositories' +check treats the four the same way, as the core whose health the mesh itself defines rather than a +module's own. It is not a catalogue module: it has no manifest, is not assigned or unassigned, and +carries no `invokes` grant of its own in a manifest, because there is no manifest. Its code lives +under `node-tools/` in the `mesh-tools` repository (`internal/console`, `internal/announce`, +`internal/bus`), and `mesh-host` and `mesh-controller` supervise, compose and account for it as a +core process rather than as an assignment (`ComponentNodeTools`/`BusNodeTools` in both, the witness +and lease code that restarts and rolls it back, the account named `.node-tools` on the bus). + +**One runtime per node, run by the node-engine as a sibling process, never a container** +(ADR 0175). It holds the node's one bus credential and may call every tool on the mesh; its account +publishes nothing else. It binds `127.0.0.1:` and refuses to bind anything else, said before +binding rather than after (`node-tools/internal/console/http.go`, citing ADR 0152): whoever is on +the machine owns the mesh there, and nobody else may reach this port. An agent or a person on the +node is pointed at `http://127.0.0.1:/mcp` once; the `serverInfo.name` the handshake answers +is `mesh`. ## What it answers -`initialize`, `tools/list`, `tools/call`, over HTTP, one JSON body per request, no session and no event -stream. `tools/list` is what the running modules answered: every tool runner built on or after that day -serves a `tools` verb for its module, and the mesh MCP server asks the catalogue for the roster and each module -for its tools. A module that did not answer is named in the list's `_meta.notAnswering`. On the day it -shipped that was 36 of 51 modules — those that serve no tools at all, and those whose rebuilt runtime the -mesh records rather than rolls out — and 62 tools from the rest. +`initialize`, `notifications/initialized`, `ping`, `tools/list`, `tools/call`, over HTTP, one JSON +body per request, no session and no event stream (`node-tools/internal/console/mcp.go`). -`tools/call` reaches any tool by `.`, listed or not. The mesh MCP server's grant is `*`, so what it -may call is every tool on the mesh; its account may publish nothing else and subscribes nothing. +**It announces seven tools, not five** (ADR 0195, extended by ADR 0367): `mesh_overview`, +`mesh_machine`, `mesh_search`, `mesh_describe`, `mesh_call`, `mesh_runtimes` and `mesh_wait`. The +handshake's `instructions` text names all seven and the four address forms; measured live, the four +nodes' tool runners between them answer for 103 modules and 645 tools this way, with two module +instances (`route-proxy` on two of the nodes) named as not answering rather than silently absent. -No call is refused for want of a person's approval: a tool runner serves every call it is issued, whoever made -it, and cannot tell an agent from the operator (ADR 0259 §6, issue 340). An act waits for the operator's warrant -only where its module asks first, in its own code: the agent module's instruction proposals, and the -controller's settings proposals and the actions it offers on a condition. +**Addresses, exactly as the handshake states them:** `.` for a seat held once for the +mesh (`mesh-controller.status`); `/.` for a seat every machine holds +(`/node-packet-filter.rules`); `/.` for a module assigned to one machine; +and `.` also for a module whose instances are interchangeable. A tool not listed can +still be called by address — listing is discovery, calling is the grant — and a module that is not +interchangeable is refused with the machines it runs on rather than guessed at. + +**What exists is what announced itself** (ADR 0197). Every node's tool runner answers the NATS services +protocol's `$SRV.PING`, `$SRV.INFO` and `$SRV.STATS`, one service per process, naming in each +endpoint's metadata which module, seat, scope and machine serves it. `mesh_overview` and +`mesh_machine` gather one request's answers: at least 750ms so a runtime that only just answered +`$SRV.PING` is still waited for, up to 5s for one that said it is there but has not yet sent its +full announcement — a fixed shorter window lost the largest runtime's listing once a live +measurement found how slow its round trip over the bus could be. An announcement unchanged since +last asked (by its digest) is not re-fetched, which is why `mesh_runtimes` can show a runtime +answering in under 100ms for hundreds of kilobytes of discovery. + +## mesh_wait + +**The seventh tool, added by ADR 0367**, lets a session wait on the bus for an event instead of +polling: a call names one or more granted event families and an optional filter, and either answers +the first match or says it timed out. The tool runner's own bus account hears only the families its +manifest-equivalent grant names; an event it hears is never taken as the state — a session reads the +state from the verb that owns it once woken. It is meant to be called in a loop from a background +command, not inline, because one call blocks until it answers or times out. ## The mesh's own verbs -*Since 2026-09-30 evening (ADR 0154).* -The mesh MCP server asks the `mesh-controller` seat's `tools` verb beside the modules and lists every role's -tools as `.` — `mesh-controller.status`, `mesh-controller.push` and the other ten. A call -to `.` reaches the seat when the prefix is a seat declaring that verb, and the module -otherwise; `seat:.` says so outright. When the controller does not answer, the list -names `mesh-controller (seat)` as not answering and carries the modules' tools regardless. The -`mesh-controller` *module* is always named as not answering: it serves no module tools, only its seat's. +**These already answer directly, not as a stated future.** Beside every assigned module's tools, +the tool runner asks the `mesh-controller` seat for its own verbs the same way (ADR 0154): measured +live, that seat answers between 60 and 93 verbs per node (`status`, `push`, `assign`, `build`, +`artifacts` and the rest), and the `mesh-controller` *module* answers none of its own — it serves no +module tools, only its seat's, exactly as design 33 described while it was still only designed. -## Around it +## Where it runs -- **`invokes`** in a manifest is the grant. It is composed into the bus's user list exactly as a - person's account is; the mesh MCP server is the only module that declares it. -- **`module check …`** on the controller's binary judges a manifest with no mesh: the strict - parse, every per-manifest problem, and the rules between the manifests given. It prints what it cannot - judge without a store rather than refusing. The mesh MCP server's own manifest was the first thing checked - with it, and the whole catalogue passes. -- **The person's client remains.** `operator issue` and `mesh tools|call|mcp` with a credential file - still work, for a machine that is not a node and for a mesh not yet able to assign anything. - `mesh tools --console ` goes through a running mesh MCP server with no credential; it is covered by the - runtime repository's tests and was not exercised on the live mesh. +**Every node, not a per-operator assignment.** Measured live: all four of the mesh's machines +answer a `node-tools` runtime, each with its own module and tool count (between 294 and 312 tools, +56 to 93 seat verbs, in this reading). This is a fact that shipped past the design it came from: the +to-be document this amends still describes it as assigned to "whichever machines an operator sits +at"; what actually runs is the opposite — every node the mesh holds carries one, because it is core +infrastructure the mesh itself depends on (discovery, the controller's own verbs, every module's +tools), not a convenience assigned to a workstation. There is accordingly no assign or unassign verb +for it: removing it from a node is not an operation the controller or the catalogue exposes. -## What shipped bent +## What this repository's prior text got wrong -- A module registered by hand from the catalogue with `--source --path modules/` records a URL, - not a place on the git seat: `--self` takes the forge path form (`/`), which the - operator did not pass. The rebuild-on-merge matched the URL anyway. -- Modules whose upgrade policy is *record* — the forge among them — answered `tools` only once - something pushed their rebuilt runtime; until then they are listed as not answering while still - callable. That is the policy doing what it says, not a fault of the mesh MCP server. +The document this replaces described `mesh-console` as a catalogue module with an `invokes: ["*"]` +manifest, served by a container, assigned only to workstations, and implemented in TypeScript +(`mesh-tools src/mesh.ts`, `src/http.ts`, `src/runtime.ts`). None of that is true of what runs today: +the container, the manifest, the per-workstation assignment and the TypeScript implementation are +all gone, replaced in substance by ADR 0175's host-side, module-agnostic, Go runtime described +above. The quirks it recorded from the `mesh-console` era (a module registered by hand recording its +source as a URL; a *record*-policy module staying listed as not-answering until its rebuilt runtime +is pushed) are not re-checked here: they were about the `mesh-console` container's registration path, +which no longer exists. + +## How it is checked + +- `mesh_overview` and `mesh_machine `: the live tool and seat-verb counts, and which modules + are named not-answering. +- `mesh_runtimes`: which runtimes answered discovery, how long they took, how large their + announcement was, and whether it was shortened to fit the bus — read this when an address is said + to be missing or on another machine. +- `mesh_describe
` for one tool's schema; a call through `mesh_call` reaches the module or + seat over the bus and the answer is its own, unshaped. +- The code: `mesh-tools` (`node-tools/internal/console`, `internal/announce`, `internal/bus`), + `mesh-host` and `mesh-controller`'s core-component handling of `node-tools` (witness, lease, + bus-user naming). Their unit tests hold the loopback-only refusal, the seven-tool handshake, the + discovery gather window and `mesh_wait`'s event-then-read-state rule. +- `knowledge-base.get` with `kind: decision` and number 152, 175, 195, 197, 367 or 154. diff --git a/03-DESIGN/01-to-be/34-the-console.md b/03-DESIGN/01-to-be/34-the-console.md index 08f4a59e..1f246502 100644 --- a/03-DESIGN/01-to-be/34-the-console.md +++ b/03-DESIGN/01-to-be/34-the-console.md @@ -1,11 +1,13 @@ --- layer: to-be -status: designed -code: [mesh-catalog, mesh-tools, mesh-controller] -updated: 2026-10-03 +status: implemented +code: [mesh-tools, mesh-host, mesh-controller] +updated: 2026-10-17 decisions: - "ADR 0197" - "ADR 0195" + - "ADR 0175" + - "ADR 0367" - "ADR 0160" - "ADR 0159" - "ADR 0152" @@ -163,11 +165,16 @@ matched it by URL. ## What this does not settle -- Narrowing a mesh MCP server's grant per assignment. ADR 0046 makes it a setting; nothing reads one yet. -- The mesh's own verbs on the bus. Design 33's third family; this document only says where they appear - once they exist. -- A person's identity behind the mesh MCP server. The mesh sees the mesh MCP server's account; design 15 keeps the - question open. +- **The mesh's own verbs on the bus.** Design 33's third family: these now answer directly, through + the `mesh-controller` seat, under ADR 0154 — settled, not open. [As-is 13](../00-as-is/13-the-console.md) + records it live. +- **Narrowing the tool runner's grant per assignment.** ADR 0046 makes it a setting; nothing reads + one yet. Owned by [design 58](58-agent-work-as-the-meshs-own.md) milestone 6 (issue 883): an + identity asked for each assignment is one of that milestone's parts. +- **A person's identity behind the mesh MCP server.** The mesh still sees only the tool runner's own + account, never the caller's; design 15 raised the question and leaves it open. Owned by the same + milestone (design 58 milestone 6, issue 883): its outcome is that every person, agent and module + becomes an identity with a role, and a call carries which one made it. ## References