Generating the directory
mcp-beaver directory -o <dir> sweeps the official MCP registry and writes a
directory of what its servers actually serve: a record of the sweep, one
mcp-upstream guardfile per answering server, and two pages that index
them. It is pull run across the registry, plus the pages. Spec:
mcp-beaver#121, following the prototype behind mcp-beaver#119.
mcp-beaver directory -o out # the whole registry, read-only
mcp-beaver directory -o out --limit 40 --scope all # the first 40 listed, every declared tool
mcp-beaver directory -o out2 --from out/sweep.json # re-render offline from an earlier sweep
What it writes
sweep.json- every server the registry listed, answered or not, with its state, description, published date, repository, and each tool's name, description, andreadOnlyHintexactly as declared. An absent hint is absent in the file too, never folded into false. This is the only input the rest needs, so--fromrenders it again without the network.guardfiles/<name>.mcp.kdl- one per answering server,/in the registry name written as__, through the same rendererpulluses and parsed back before it is written. The rules arepull's and unchanged: allow on the declared hint never the name, nowithholdblocks, no guessing, upstream order.index.html- the directory. Counts for the run, one row per answering server with its tools split into declared read-only, declared mutating, and undeclared, itsannotation-coverage, and a link to its guardfile. Then the refusals with their state.guardfiles.html- every guardfile, grouped by coverage.
What it does
GET <registry>/v0/servers?limit=100, followingnextCursor. KeepisLatestandstatus: activeentries that publish astreamable-httpremote, first remote wins, one entry per name.--limitcaps the count in registry order.- Probe each entry the way
pulldoes,--concurrencyat a time and--timeoutper upstream, 30s by default. A refusal is that server's state,HTTP 401when the upstream answered a status,timeoutwhen it ran past the deadline, and the transport's own words otherwise, and never the sweep's failure. Half the registry refuses anonymously, and a directory that stopped at the first 401 would never be written. One line per server goes to stderr as it settles, so a long sweep is visibly moving. - Record, emit, and render from the record.
No credential is presented. The refused half stays outside the corpus, which
is the measurement the spec recorded, and pull --upstream-header remains
the way to reach one of them by hand.
The counts are the hint, not a name
The index counts on readOnlyHint alone. The prototype's page classified
tools by their names, and mcp-beaver#118 measured that screen at 6 of 24 real
mutators, with payment tools among the misses. A directory column that
disagrees with the guardfile beside it is the one thing this page must not
do, so the heuristic feeds nothing here. A tool declaring nothing is counted
as undeclared rather than guessed at.
See also
- pull.md - one server, the same renderer, and the scope axis.
- registry-pull.md - the Python prototype this replaces the index and guardfile pages of, and the 2026-09-01 corpus.
- upstream.md - the proxy each generated file configures.