In one line: treat a tool as a content-addressed artifact, run it inside a sandbox, and keep an identity behind it — only then does “trusted” mean anything. That is the architecture; the second half of this article is the implementation.
1. The problem: an agent’s tools are black boxes
An agent’s capability is not bounded by its model. It is bounded by the tools it can actually call. And today’s tools are black boxes: third-party code, one container per tool, centrally hosted.
| Consequence | What it looks like in practice | The price |
|---|---|---|
| Unverifiable | You don’t know which bytes are running, or whether they changed | You won’t hand it sensitive data |
| Unportable | One native binary per ISA (x86 / ARM / RISC-V) | The tool never reaches the edge |
| Unscalable | One container per tool: 527–1119 ms cold start, 69–94 MB resident | A small device can hold three of them, not thirty |
This is not an operations problem. It is a trust problem: you cannot check the tool, you cannot move it, and you cannot run it on demand.
2. Where the research stands
Work on “MCP + WebAssembly” over the last two years has framed the problem cleanly. Three gaps, and a set of responses (figures and design claims below come from published work; measurements are from an Intel NUC):
Gap 1 — the protocol carries functional metadata only. A tool schema says what a tool is called, what it takes and what it returns. It says nothing about how long it runs, whether it is CPU-bound, where its data lives, or whether that data may leave the device. A scheduler is blind.
Gap 2 — cold start and instruction sets keep the edge out. Containerised MCP servers take 527–1119 ms to start and sit at 69–94 MB resident. Native binaries need a build per ISA. In one dataset of registered servers, 22.3% supported stdio only, 77.7% HTTP only, and 0% supported both — the transport is frozen at build time.
Gap 3 — the SDKs are bound to OS primitives. They assume threads, signals and sockets. WASI has none of them, so the WebAssembly side has no native transport layer and falls back to a sidecar proxy — which hands back every resource Wasm was meant to save.
The research response comes in three groups:
| Layer | Claim | What it means for the architecture |
|---|---|---|
| Control plane | proxy → registry + profiles → constraint filter → pluggable scheduler | separation of what to run from where it runs; candidates collapse from N×M to N |
| Runtime | dual transport from one source, compile-time schema, stripped init path | 53 ms start; no sidecar; portable across architectures |
| Deployment | stateless HTTP, scale-to-zero, a wasmtime runtime class, volumes mapped to preopens | WebAssembly modules can live in a cluster and read storage |
The scheduler scores a candidate as:
1Score = α · Pexec + β · Pnet + (1 − α) · Pcomm
Pexec is normalised execution latency, Pcomm the communication cost to that node, β adds external network latency Pnet for network-bound tools, and α trades computation against transfer per tool type.
3. The architecture
Research gives parts; parts are not an architecture. The design I would defend has four requirements and two principles.
| Requirement | What it solves | What breaks without it |
|---|---|---|
| Content-addressed distribution | the artifact is immutable and checkable | you trust whatever a service says its version is |
| Sandboxed execution | untrusted code cannot leave its box | third-party tools inherit host privileges |
| Traceable identity | you can attribute publishing and calling | nobody is answerable in a network without a centre |
| Standard MCP protocol | any agent framework can connect | one adapter per framework |
The two principles are decentralized (distribution does not depend on a central registry) and trusted (immutable + sandboxed + attributable, all three at once).
In a running system that is three layers plus two lateral capabilities:
Five invariants follow, and every implementation decision is measured against them:
- One logical tool. The caller sees a tool name, never a node.
- Pluggable control plane. Scheduling algorithms and constraints change without touching orchestration.
- Replaceable execution plane. The same tool semantics can run as WebAssembly or as a container.
- Immutable artifact. Once published, the address is the checksum.
- Attributable identity. Every publish and every call lands on an address.
4. Implementation: five layers
The implementation below is open source (Apache-2.0 / MIT). Its five layers map one-to-one onto the requirements, and each has a code anchor you can open.
4.1 Manifest: a tool is a catalog entry, not a deployment unit
1modules:
2 - name: hello
3 wasm_path: IPFS://QmeDsaLTc8dAfPrQ5duC4j5KqPdGbcinEo5htDqSgU8u8Z
4 tools:
5 - name: say_hello
6 description: Greet someone by name
7 inputs: [{ name: name, type: string, required: true }]
Adding a tool edits this one file. Nothing is rebuilt; the runtime registers what the manifest declares.
4.2 Runtime: untrusted code goes into a sandbox
1// core/mcp/wasm.go (excerpt)
2if strings.HasPrefix(path, "IPFS://") {
3 data, _ := ipfs.ExtractWASMFromCID(client, strings.TrimPrefix(path, "IPFS://"))
4 for _, d := range data { manifest.Wasm = append(manifest.Wasm, extism.WasmData{Data: d}) }
5}
6cfg := extism.PluginConfig{ModuleConfig: wazero.NewModuleConfig().WithSysWalltime(), EnableWasi: true}
The sandbox buys two things: untrusted code cannot escape, and the same bytes run on x86 and ARM.
4.3 Distribution: the address is the hash
Change one byte and the CID changes. Publishing a tool therefore means publishing a content address: anyone can verify what they run, with no central registry involved. This layer is the part of “decentralized” that is actually hard.
4.4 Identity: an attributable slot in a network without a centre
At startup the service decrypts a keystore with a passphrase and gets an address. Today it is identity only — no metering, no billing. First you establish who published and who called; authorization and settlement come later.
4.5 Protocol: catch every agent, then dare to enter a cluster
MCP runs over Streamable HTTP with the registry exposed at GET /tools. Stateless requests are what allow scale-out and scale-to-zero — the real difference from a resident SSE server.
5. Four trade-offs and what they cost
An architecture is a list of trade-offs. Each one is written with its cost, or the next version pays for it again.
| Decision | Alternative | Why | Cost |
|---|---|---|---|
| Manifest-driven | dynamic registration at runtime | config is the contract; small audit surface; tool code stays out of the runtime | hot updates need a manifest reload |
| IPFS distribution | central registry | immutable, verifiable, globally fetchable | the first fetch pays a network round trip (published p99: 50 ms) |
| Wallet identity | API keys / OAuth | self-verifiable in a network without a centre | today: identity only, no permission model |
| Stateless HTTP | resident SSE | scale-to-zero, horizontal scale | loses long-lived push semantics |
One item on the list is not a trade-off but a debt: one instance per module with a single lock, so concurrent calls to the same tool queue. It keeps module state safe and caps throughput; an instance pool is the next step.
6. Where it stands against the research design
The gap is easy to state: runtime, distribution and identity are shipping; the control plane is not. It runs — it is not smart. A human still decides which layer a tool lands on.
That is also why the control plane is drawn grey in Figure 2: part of the design, not yet implemented.
7. Numbers, with their sources
| Metric | Value | Source |
|---|---|---|
| Module start | 53 ms | measured (Intel NUC) |
| Container start | 527–1119 ms | measured (same) |
| Cold-start gap | 10–21× | measured |
| Memory | 31 MB vs 82 MB (−59~72%) | measured |
| Distribution size | 0.3–1.4 MB vs 80–167 MB image | measured |
| Constraint violations (45 calls) | 0 vs 41 / 42 / 42 | measured |
| End to end | 2.3× faster than all-cloud | measured |
| Throughput / avg response / IPFS p99 | 25,000+/s, 5 ms, 50 ms | vendor-published, not independently re-measured |
The last row matters: it is not our measurement. Vendor figures must be separated from measured ones wherever they appear, or one number drags the whole article down.
8. Trust is a product of three conditions
Here is a check a reader can perform: take the CID, fetch it yourself, hash it, compare with the address that was published. If they differ, what you got was modified. Trust means you can check it yourself — a property that does not depend on any company’s promise.
9. Roadmap and open questions
- Control plane: runtime profiles → constraint filtering → placement. The goal is to move “which layer does this tool land on” from a human decision to a system decision.
- Concurrency: one instance, one lock → an instance pool.
- Cold path: caching and prewarming for the first fetch.
- Open: should placement be exposed to tool authors? Who defines constraints — the platform, the data owner, or the caller? The answers decide whether this ends up a runtime or a market.
References
- Published work: Orchestrating WASM-based MCP Tool Runtimes for AI Agents across Edge-Cloud Continuum (CCGrid 2026) — the three gaps, the control plane, the WASI-native runtime and the measurements above.
- Implementation: DANP-LABS/DANP-Engine (Apache-2.0 / MIT).
- Project site: danp.icefirelabs.xyz.




