{"id":225,"date":"2026-09-01T16:23:04","date_gmt":"2026-09-01T14:23:04","guid":{"rendered":"https:\/\/zeryon-systems.com\/blog\/?p=225"},"modified":"2026-09-01T16:23:05","modified_gmt":"2026-09-01T14:23:05","slug":"a-tool-that-is-available-is-not-yet-a-tool-that-is-allowed","status":"publish","type":"post","link":"https:\/\/zeryon-systems.com\/blog\/2026\/09\/01\/a-tool-that-is-available-is-not-yet-a-tool-that-is-allowed\/","title":{"rendered":"A tool that is available is not yet a tool that is allowed"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">A tool that is available is not yet a tool that is allowed<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Where AXYON stands today \u2014 and the MCP Control Layer we are building<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Connect an MCP server to an agent and you get back a list of tools. From that moment on, the agent can call them. Between &#8222;it is on the list&#8220; and &#8222;it may be used&#8220;, the protocol contains nothing that makes a decision. The tool name comes from the server. So does the description. So does the input schema. None of it is verified.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is not a flaw in the specification. MCP is a connection protocol, not a security layer, and the maintainers say so themselves: the information a server presents about itself should explicitly not be relied upon for security decisions. The problem starts where someone runs the chain the way it comes out of the box. The model plans, the tool is there, the call goes out. The log entry comes afterwards.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The problem is that order, not the individual call.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What guardrails and audit trails do not do<\/h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"585\" src=\"https:\/\/zeryon-systems.com\/blog\/wp-content\/uploads\/2026\/09\/A-tool-that-is-available-is-not-yet-a-tool-that-is-allowed-1-1024x585.jpg\" alt=\"A tool that is available is not yet a tool that is allowed\" class=\"wp-image-228\" srcset=\"https:\/\/zeryon-systems.com\/blog\/wp-content\/uploads\/2026\/09\/A-tool-that-is-available-is-not-yet-a-tool-that-is-allowed-1-1024x585.jpg 1024w, https:\/\/zeryon-systems.com\/blog\/wp-content\/uploads\/2026\/09\/A-tool-that-is-available-is-not-yet-a-tool-that-is-allowed-1-767x438.jpg 767w, https:\/\/zeryon-systems.com\/blog\/wp-content\/uploads\/2026\/09\/A-tool-that-is-available-is-not-yet-a-tool-that-is-allowed-1-300x171.jpg 300w, https:\/\/zeryon-systems.com\/blog\/wp-content\/uploads\/2026\/09\/A-tool-that-is-available-is-not-yet-a-tool-that-is-allowed-1.jpg 1344w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Guardrails sit in front of language. They check what a model is allowed to say, and they do that well. But the damage is not the wording \u2014 it is the write into the target system, the record that leaves the building, the deletion nobody asked for.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Audit tooling sits behind the event. It records what happened, which matters and is indispensable in a review. It just does not answer the question that gets asked first when something goes wrong: who approved this?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Together they produce a chain in which nobody decides. The common mistake here is to treat that as a documentation gap. It is a gap in the chain of effect.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The question AXYON is built around<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/zeryon-systems.com\/axyon\/\" target=\"_blank\" data-type=\"link\" data-id=\"https:\/\/zeryon-systems.com\/axyon\/\" rel=\"noreferrer noopener\">AXYON <\/a>is an execution control layer. Before every single action it answers one question: may this action run? AI proposes, AXYON decides.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In practice: a task carries its own tool boundary. An approval applies to exactly that task, applies once, and is bound to the content \u2014 if the content changes, the approval is worthless, and that is not open to discussion after the fact. Whoever approves cannot be whoever requested. And since late August the appliance additionally checks whether the approver is a human being at all. The subject kind is established server-side from authentication, never taken from the caller. The default is &#8222;machine&#8220;. Anything that does not identify as human approves nothing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That default is the inconvenient one, deliberately. A rule that lets things through when in doubt is not a rule.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On top of that comes what a security lead expects from runtime control anyway: revocation during a run, an emergency stop that actually takes effect, and a record that does not belong to the application. About that record we speak plainly. It is cryptographically chained, keyed-signed and externally witnessed. It is not &#8222;audit-proof&#8220; in the legal sense \u2014 that term promises a legal consequence the mechanism does not carry, so we do not use it. The independent verifier shipped with it proves that a presented extract matches the witnessed state and that nothing was truncated. It does not prove the integrity of the keyed chain, because that would require the verifier to hold the key, and it does not get the key.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">AXYON comes in two form factors: a container appliance inside your own network, and a native macOS app with no open port. The interfaces may diverge; the governance may not. That is why the governance state carries its own version number, declared by every artefact \u2014 otherwise &#8222;identical in both form factors&#8220; would be a claim nobody could check.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why MCP gets a layer of its own<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">MCP has done in a short time what a good protocol does: it has driven integration cost close to zero. That is exactly what creates the problem. A company that had three hard-wired integrations yesterday has forty tools from six servers tomorrow, two of which were not built in-house.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We are building the <strong>AXYON MCP Control Layer<\/strong> for that: a separately licensed add-on that enforces at the MCP boundary what the appliance decides. The principle the entire product boundary hangs on: AXYON stands alone, MCP plugs in. The appliance runs completely without the add-on, knows nothing about MCP, and the dependency runs in one direction only. Remove the add-on and you get a working appliance back \u2014 that is an acceptance test, not a promise.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What the layer enforces follows one chain we put in front of everything else:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tool available is not tool authorized. Tool authorized is not action authorized. And <a href=\"https:\/\/garion-ai.de\" target=\"_blank\" data-type=\"link\" data-id=\"garion-ai.de\" rel=\"noreferrer noopener\">action authorized is not action authorized <\/a><em>now<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Identity.<\/strong> A tool is not recognised by its name. A name is display text any server chooses freely, and two servers may use the same one. The layer maintains a four-part identity for each tool: server identity, tool identity, schema binding, and the mapping onto AXYON semantics. If a server changes the input schema, it is a different tool and falls back into a state in which it may not be used. Name collision, substitution, silent schema drift and re-registration under a known name are all caught by the same rule.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Server identity does not come from the protocol.<\/strong> It cannot, because the protocol does not verify it. Over HTTP the layer requires TLS and a per-server anchor held on our side; the endpoint URL is an address, not an identity. For locally launched servers the test is the digest of the artefact together with the exact launch specification, checked before start. A path is not an identity. A name that suddenly appears with a different cryptographic identity inherits no trust; that requires an authorised lifecycle event.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Version.<\/strong> The supported protocol revision is pinned. There is no automatic fallback to an older revision, because a silent protocol downgrade is precisely the attack that version binding exists to prevent. An unknown revision is rejected, not interpreted. The legacy SSE transport is not supported.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>No side channels.<\/strong> The current specification lets a server have parameter values mirrored into HTTP headers. Those values go into the parameter hash in full. Anything else would be a channel alongside the authorised action, and the approval would cover something that was never requested in that form. For the same reason we do not support the callback paths through which a server can demand a model response or human input from the client. An approval dialog inside the add-on would be a second decision authority, and two decision authorities are worse than one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Above all: no allow authority of its own.<\/strong> The layer may deny, validate, rate-limit and apply backpressure. It may not permit anything. No cached yes, no default, no &#8222;it was allowed last time&#8220;, no continuing to run when the appliance is unreachable. No authority means no new execution. It can reduce authority, never increase it. No language model sits in that path.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Evidence before effect.<\/strong> From medium risk upwards: no durably written record, no execution. For low-risk reads, bounded backpressure is allowed, but nothing is dropped to keep throughput up. There is no best-effort logging. Low risk does not mean evidence is optional.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Executed but unverified is not success.<\/strong> If an action went out and confirmation is missing, that is a state of its own, not a checkmark. The affected resource is locked, and the lock is released by a human at the appliance \u2014 not by the add-on, because an add-on that releases locks is increasing its own authority.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Where this stands today<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The appliance and the macOS app are available, and the v1.0 line is set. Everything beyond that I would rather describe myself than have someone find while checking.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The authorization foundation \u2014 canonical encoding, authorization object, binding to content and effect, replay protection \u2014 is built and tested. Enforcement in the production path is therefore not yet wired; that is the next integration step, and we track it as a finding, not as a feature.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The MCP Control Layer is decided in architecture and boundaries. The contracts between add-on and appliance are in progress and not yet frozen, and implementation follows after that. There is no date, and I will not name one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We name what is still missing as well. Per-action checking does not see accumulation: twenty individually permitted accesses can add up to something that would never have passed as a single request. The path there is decided and planned; it is not built. The latency budget for the MCP layer is defined and not measured; as long as it has not been measured, no number appears here either.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We do not name customers, not on request and not for a discount. In this field discretion is not reticence, it is part of the service. The burden of proof sits with architecture, verification tooling and supply-chain evidence instead.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The next sensible step<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you run agents in your organisation, or are deciding whether to: take one real agent path, we walk through it in an hour, and at the end you have a list of the actions that take effect today without approval. The list is yours, whether or not we work together afterwards.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Every Agent. Every Action. Before Execution.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A tool that is available is not yet a tool that is allowed Where AXYON stands today \u2014 and the MCP Control Layer we&hellip;<\/p>\n","protected":false},"author":1,"featured_media":227,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-225","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-allgemein"],"_links":{"self":[{"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/posts\/225","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/comments?post=225"}],"version-history":[{"count":3,"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/posts\/225\/revisions"}],"predecessor-version":[{"id":230,"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/posts\/225\/revisions\/230"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/media\/227"}],"wp:attachment":[{"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/media?parent=225"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/categories?post=225"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zeryon-systems.com\/blog\/wp-json\/wp\/v2\/tags?post=225"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}