Part of The Static Agent Web — the verified, serverless agent ecosystem
CI npm

Static MCP: your tools are files, not servers.

Publish an MCP tool as a static, hash-verified file. Run it sandboxed, on demand, with zero infrastructure — the way static site hosting did to web servers: don't run Apache, publish HTML.

terminal
npx -y @rckflr/mcpwasm https://mauricioperera.github.io

Running someone else's tool code is a trust decision

MCP clients like Claude or Cursor can call arbitrary third-party tools. Executing that code directly in your backend means it can read your secrets, hit your database, phone home, or loop forever. You either trust the author fully, or you don't run the tool.

Typical MCP server

  • Someone has to run a process, 24/7
  • Third-party code shares your runtime
  • Trust the author, or don't install

mcpwasm

  • The tool is a file. No process to run.
  • Code executes isolated in QuickJS-wasm
  • SHA-256 pinned; a flipped byte excludes it

How it works

Five steps, all sandboxed, no state kept between requests.

A publisher site ships llms.txt and tool.js; the gateway fetches and verifies them by SHA-256, loads the tool into a QuickJS-wasm sandbox, the sandbox calls host.fetchOrigin back to the publisher, and the MCP client gets a JSON-RPC response. Publisher site static: R2 / Pages / any host serves /llms.txt + tool.js Gateway discover → verify sha256 load into sandbox MCP client Claude, Cursor, ... POST /mcp (JSON-RPC 2.0) Sandbox QuickJS-wasm, per skill 1 publish 2 verify sha256 3 load 4 fetchOrigin 5 JSON-RPC
  1. A publisher site ships /llms.txt plus per-skill tool.js and SKILL.md.
  2. The gateway downloads llms.txt, fetches each tool.js, and verifies its SHA-256.
  3. Verified tools load into a fresh QuickJS-wasm context, one per skill.
  4. Tool code calls host.fetchOrigin — scoped to the publishing origin only; anything else throws inside the sandbox.
  5. The gateway maps MCP tools/list / tools/call over JSON-RPC 2.0 back to the client.

Four ways to use it today

All four are real, deployed, and tested — not roadmap.

Gateway turnkey MCP server

Point any MCP client at the deployed gateway. It discovers, verifies, and sandboxes a publisher's skills on every request.

bash
curl -s -X POST \
  "https://llmstxt-gateway.rckflr.workers.dev/mcp?origin=<url-encoded-origin>" \
  -H "Authorization: Bearer <AUTH_TOKEN>" \
  -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Local runtime zero infra, both sides

Run any origin's skills locally over stdio — including origin memory (verified BM25 search, 0.4.0), each skill's SKILL.md recipe served as an MCP resource (0.5.0), and multi-project origins via scopes: kdd__search_knowledge with per-scope memory (new in 0.6.0). No gateway, no server, on either end.

bash
npx -y @rckflr/mcpwasm https://mauricioperera.github.io

Library embed the sandbox

Build your own platform host with the exact isolation the gateway uses.

js
import { AsyncToolHost } from "@rckflr/mcpwasm";

const host = new AsyncToolHost({ allowedOrigin: "https://example.com" });
await host.init();
host.loadToolSource(toolJsSource);
const result = await host.callTool("sum_numbers", { a: 2, b: 40 });
host.dispose();

Browser runtime no Node either

The whole runtime in a browser tab (new in 0.7.0): discovery, byte-for-byte SHA-256 verification, one QuickJS-wasm sandbox per tool, scopes and per-scope memory. The publisher only needs CORS — GitHub Pages already sends it. No server on their side, no Node on yours.

js
import { connectStaticSkills } from "@rckflr/mcpwasm/web";

const skills = await connectStaticSkills("https://mauricioperera.github.io", opts);
await skills.callTool("search_knowledge", { q: "how do I publish?" });

Open the live demo Full-stack agent demo

The whole stack, as one personal agent

tab-agent is a personal AI agent that is nothing but static files + your browser: shared memory (the cq-git commons over the GitHub API), verified tools (this runtime, hash-pinned & sandboxed), and a model you own — the provider credential is never exposed (run it in-tab via WebGPU, your endpoint, or an operator proxy). It answers the personal-agent supply-chain problem by inverting it: tools are verified, not screened.

Open tab-agent

Three rings of trust

None of them alone is enough. Together, they bound what a third-party tool can do — and who vouches for it.

01

Content integrity

Every tool.js is pinned by SHA-256 in llms.txt. A single flipped byte and the skill is excluded — not degraded, not executed.

02

Sandbox isolation

Each skill runs in its own QuickJS-wasm context: no fetch, no process, no disk. The only bridge out is an explicit, origin-scoped host.fetchOrigin.

03

Signed attestations

Signed human review with an expiry window — pre-registered Ed25519 keys or keyless Sigstore identities (the spec's recommended default since v0.4). Honest today: one registered reviewer. The mechanism scales; the reviewer network hasn't yet.

What it costs

Real numbers from the deployed gateway, not synthetic estimates.

0ms
sandbox overhead, warm
55ms sandboxed vs 53ms raw ping
0ms
full gateway overhead
96ms via gateway vs 90ms direct API
0ms
p95, 10 concurrent requests
before → after the instance pool + preheat
0ms
cold discovery miss
~210–400ms range, compile + sha256 + fetch

Single-client benchmark from México to the Cloudflare Workers edge — this is latency of one observer, not a load test. Full matrix, methodology, and raw data are in BENCHMARK.md.

Try it now

Run any origin's skills locally, no gateway

bash
npx -y @rckflr/mcpwasm https://mauricioperera.github.io

MCP client configuration

json
{
  "mcpServers": {
    "misitio": {
      "command": "npx",
      "args": ["-y", "@rckflr/mcpwasm", "https://mauricioperera.github.io"]
    }
  }
}

Or call the live demo gateway directly

bash
curl -s -X POST \
  "https://llmstxt-gateway.rckflr.workers.dev/mcp?origin=https%3A%2F%2Fllmstxt-demo-site.rckflr.workers.dev" \
  -H "Authorization: Bearer <AUTH_TOKEN>" \
  -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"sum_numbers","arguments":{"a":2,"b":40}}}'

The deployed gateway requires a bearer token (not published here). Full curl walkthrough — including the open demo, bookstore, and docs publishers — is in the README.

From a static site to a live MCP server

llms-txt-skills is the format; mcpwasm is a runtime for it. A publisher serves hash-pinned, attested skills once, the standard way — the runtime discovers, verifies, and runs each as an MCP tool. The whole contract between them is one tool_sha256 and its attestation.

A static publisher site serves llms.txt skills and tool.js; mcpwasm fetches and verifies them, then exposes each as an MCP tool that a client can call, running the tool.js sandboxed. Static site llms.txt · ## Skills · tool.js index.json · attestations.json mcpwasm runtime gateway (Workers) or npx local verify + QuickJS sandbox MCP client Claude, Cursor, any MCP host lists and calls the tools 1 fetch + verify 2 serve as MCP tools 3 call tool(args) 4 sandboxed tool.js
  1. A publisher serves an llms.txt whose ## Skills section lists each executable skill with its tool.js and tool_sha256 — mirrored in /.well-known/agent-skills/index.json and signed in attestations.json. Optionally, a hash-pinned BM25 snapshot (one llms-skills memory command over an OKF bundle) adds serverless search over the site's own knowledge. This is exactly what the llms-txt-skills spec defines. Since llms-skills 0.4.0, the bundle can also carry signed freshness: a reviewer attests “still true”, voided on edit, expiring on a date.
  2. mcpwasm points at that origin, fetches the llms.txt, and verifies every tool.js against its tool_sha256 and its attestation — rejecting any mismatch before loading it.
  3. Each verified skill becomes an MCP tool, and its SKILL.md recipe is served alongside as an MCP resource (with a get_skill_guide fallback) — the agent gets the manual, not just the hammer. Claude, Cursor, any MCP host list and call it like any other tool.
  4. On a call, mcpwasm executes that tool.js verbatim inside a QuickJS-wasm sandbox — no network or filesystem except the host capabilities it grants (a scoped fetchOrigin back to the site, and search over the site's own content). The result returns to the client.

Neither side has to trust the other's prose: mcpwasm re-derives the hash and checks the signature itself. Static hosting + a verifying runtime = an MCP server with no server to run.

Want to be the publisher side? Start from the GitHub template — a working publisher out of the box (example knowledge bundle, generated skills, validation CI) that this runtime consumes as-is.

Part of a spec, not just a repo

mcpwasm is the reference implementation of two provisional extensions to the llms-txt-skills standard: Executable Skills (v0.5, with origin memory and scopes) and Skill Attestations (v0.4). Every MUST in those specs is field-tested in this code — spec and implementation are kept in sync.