v0 · experimental · Apache 2.0 · the binary protocol Prowl uses

Read any URL. Invoke any API. One binary protocol.

Mycelio is the binary layer agents use instead of HTTP+JSON. One persistent connection gives an agent two things: FETCH any public URL as clean Markdown (~30× fewer tokens than raw HTML), and ROUTE calls into signed vendor manifests without touching their docs. Every response is Ed25519-signed by the directory.

daemon live · myc://mycelio.prowl.world:4242 100 tests · Apache 2.0 v0 — no major agent runtime speaks this yet

01Read any URL

Point Mycelio at any public URL. The daemon fetches it, extracts the main content as Markdown locally with trafilatura, falls back to Jina Reader for SPAs and PDFs when needed, and returns it inside a signed binary envelope. No API key. No SDK on the vendor's side. Cached 24 hours.

Or from your terminal: curl https://mycelio.prowl.world/r/<any-url>
# pip install mycelio
import asyncio
from mycelio import MycelioClient

ROOT_PUBKEY = bytes.fromhex(
    "23f6ebbc8faddb7ee8c9dedf2ef8e81057fb7d0bbace6ba26523452ef739c20c"
)

async def main():
    async with MycelioClient.connect(
        "mycelio.prowl.world", 4242, root_pubkey=ROOT_PUBKEY,
    ) as cli:
        page = await cli.fetch("https://news.ycombinator.com")
        print(page.content[:400])
        print(f"\n→ {len(page.affordances)} affordances extracted")

asyncio.run(main())

The response carries clean Markdown and a list of typed affordances (links, forms) the agent can act on — relative URLs are already resolved against the page. SPAs and PDFs that trafilatura can't parse fall through to Jina Reader transparently.

HTTP + raw HTML
~80 KB
~20,000 tokens to the LLM · per fetch · uncached
Mycelio FETCH
~4 KB
~700 tokens · cached 24h · 50 affordances typed

Measured against news.ycombinator.com on 2026-05-23. Numbers vary by page — content-heavy docs sites compress harder; static landing pages compress less. The shape holds: clean Markdown is dramatically smaller than the HTML it came from.

02Invoke any API

The whole invoke path is built around one artifact: a small signed file that points at the HTTP API the vendor already serves. Here's a representative Mycelio manifest, decoded into a readable form:

# stripe-payments.myc · 412 bytes signed

service:    stripe.com
title:      Stripe Payments API
backend:    https://api.stripe.com/v1
auth:       bearer-token (Authorization header)
endpoints:
  - op:     charge
    method: POST  /charges
    in:     { amount: int, currency: str, source: str }
    out:    { id: str, status: str }
  - op:     refund
    method: POST  /refunds
    in:     { charge_id: str, amount: int }
    out:    { id: str, status: str }
signatures:
  vendor:    ed25519:9f8a3d...
  directory: ed25519:1b4c7e...

Wire-encoded as binary frames it's 412 bytes. You sign it with your Ed25519 key. The directory co-signs it with the root key. Your HTTP backend stays untouched — Mycelio just describes how it can be reached. No SDK, no server to run, no integration to maintain.

03Where we honestly are

This is v0. The reference daemon runs at myc://mycelio.prowl.world:4242. The Python SDK is on PyPI. 100 tests pass end-to-end. The wire format is stable enough to build against.

Shipped: spec v0, binary frame codec, TLS support, async daemon, vendor manifests with Ed25519 dual signing, INSPECT, ROUTE, and FETCH verbs working end-to-end (FETCH with affordance extraction + Jina fallback). Next: Prowl Design — auto-generate signed manifests from your existing OpenAPI.

But to be straight with you, the things this is not yet:

The FETCH side dodges the chicken-and-egg — it works on any URL on the public web from day one, no vendor adoption required. That's why we shipped it first.

What we're betting on: as agents move from "tool-loop inside an IDE" to "autonomous, calling thousands of APIs a session," the chicken-and-egg flips. The only protocol that can scale to "every SaaS on the internet" is one where the vendor implements nothing — because the long tail of vendors will not deploy bespoke servers per agent runtime. If that thesis is right, this becomes the layer for it.

If the thesis is wrong: the directory's HTTP API still works, your existing OpenAPI still works, and you can ignore Mycelio. Taking the protocol bet costs you a manifest file you can sign in five minutes and revoke any time.

04How it compares to MCP

MCP and Mycelio operate at different layers and we think they're complementary, not competitive. MCP shines when the agent operator already chose your tool — the user installed your MCP server, the agent is in a tool-loop, parameters are known. Mycelio is for the layer before that: public discovery and invocation across services the agent didn't know about at startup.

That said, the technical trade-offs differ in places that matter:

Plain HTTP+JSON MCP Mycelio
Vendor must Run their API (already) Run an MCP server Sign a 400-byte file
Trust model TLS + DNS TLS + operator install Ed25519 dual-signed
Connection model Per call Per server One TCP, many services
Discovery Out of band Out of band Built-in (DISCOVER)
Wire format Text JSON JSON-RPC Binary frames
The row that matters most: "Vendor must…" A protocol where vendor participation requires deploying code can't scale to the long tail of SaaS APIs — most vendors won't ship that work. Mycelio's whole reason to exist is to be a layer where vendor adoption is gated on signing a file, not on running new infra.

We're not trying to replace MCP for tool-use inside agent runtimes, A2A for agent-to-agent messaging, or OpenAI's function-calling for proprietary tool syntax. Mycelio sits one layer earlier: public discovery and signature-rooted invocation for backends that already speak HTTP.

05For agent builders

The full composition — discover services, fetch a page, invoke an op — happens in one TCP connection. No extra TLS handshakes between verbs, one signature chain, one auth context:

async with MycelioClient.connect(
    "mycelio.prowl.world", 4242, root_pubkey=ROOT_PUBKEY,
) as cli:
    # 1. find payment APIs
    matches = await cli.discover(query="payment", min_score=80)

    # 2. read a candidate's site to evaluate it
    page = await cli.fetch(f"https://{matches.results[0].name}")
    if "x402" in page.content.lower():
        # 3. pull the manifest and invoke it
        m = await cli.inspect(matches.results[0].service_id)
        resp = await cli.route(m, "charge", {"amount": 500, "currency": "usd"})
        print(resp.json())

DISCOVER + FETCH + INSPECT + ROUTE in one session. End-to-end signature verification. Full demos in examples/. Wire spec: protocol-v0.md.

06The verbs

Seven verbs are implemented end-to-end today; four are reserved in the spec for future use. Reserved doesn't mean "coming soon" — it means "the byte is allocated so an implementation can grow into it later without breaking compatibility."

Manifest format: manifest-v0.md

07Open spec, run by Prowl

Mycelio is Apache 2.0. The wire spec, frame codec, Python SDK, and reference daemon all live in the public GitHub repo. Implementations in Go, Rust, JS are welcome.

The honest part: right now there's only one directory running Mycelio in production, and that's Prowl. The daemon at myc://mycelio.prowl.world:4242 is Prowl's. The Ed25519 root key that co-signs every manifest is Prowl's. The spec doesn't assume one operator, but until someone else stands one up, "Mycelio" and "Prowl's binary protocol" mean the same thing in practice. We'd rather say that out loud than pretend otherwise.

Lock-in worry: your manifest can be served by any future directory, your existing HTTP API is the source of truth that survives any of this, and you can revoke at any time.

08What we need from you