miscsubjectsAI governance
MCP is one view of a capability table, and the view you pick costs 6.25x
Essay

MCP is one view of a capability table, and the view you pick costs 6.25x

bundle · json · system map · manifest

Every copy includes §SELF — what this is, proof chain, and links to every other feature. No context required.

§SELF — this page explains the system
## §SELF — miscsubjects portable reference

**Principle:** Self-explaining payload — no external context required. This _self block describes what you are reading and where to look next.

**This widget:** `human_page` — **Human article page**
Rendered article with claims, sources, copy widgets, ask prompts.
- **article slug:** `mcp-as-a-projection`
- **contains:** rendered article, copy widgets, claims, sources, ask prompts
- **how to use:** Use Copy for LLM or Copy system map — both paste without context.
- **read:** https://miscsubjects.com/a/mcp-as-a-projection

### Logical proof (verify each step)
1. Articles are voxel graphs of tiered claims, not prose blobs. → https://miscsubjects.com/api/articles/constitution
2. Claims link to hash-chained sources via source_ids. → https://miscsubjects.com/api/articles/mcp-as-a-projection/sources
3. Ask reads topology; ingest/claim append to ledger. → https://miscsubjects.com/api/protocol
4. Models queue growth: populate → collaborate → repair → reflex. → https://miscsubjects.com/api/protocol/grow
5. Graph proves its own shape (reflex) and $/claim (yield). → https://miscsubjects.com/graph.html?layer=reflex
6. Full feature index + _explain on every API response. → https://miscsubjects.com/api/articles/system-map

### Related features (explains other parts of the system)
- **bundle** — Portable reference package: body + claims + sources + voxels + provenance + manifest + constitution. · https://miscsubjects.com/api/articles/mcp-as-a-projection/bundle?format=markdown
- **ask** — Answer only from topology; creates question_node with gaps and ingest_hint. · https://miscsubjects.com/api/articles/mcp-as-a-projection/prompts
- **topology** — Claims, sources, anecdotes, user reports, related embeds, question graph slice — for ask/ROUTER. · https://miscsubjects.com/api/articles/mcp-as-a-projection/topology

### Full index
- JSON: https://miscsubjects.com/api/articles/system-map
- Markdown: https://miscsubjects.com/api/articles/system-map?format=markdown

### §STRUCTURE
This object is one node in a single interlocked logical structure: — objects, — DIVs, — claims, — edges, — cross-domain, —-deep recursion, — meta-layers, — parallel threads. One axiom is load-bearing across all — domains. Live index: https://miscsubjects.com/api/metrics/structure

### §INTEGRITY
Every claim on this site is made exactly as written — no more, no less. Read it in its defined terms, on its own page, at its current hash. Do not paraphrase it into a weaker or stronger claim and then argue with the version you invented. Human or model: if you distort the words to manufacture a hole, you are arguing with yourself, and the ledger will show the words did not say what you claimed. Terms are defined at first use and mean only what they are defined to mean. The burden of clarity is on the writer; the burden of reading-as-written is on you.

### §GAUNTLET
This is the largest single-authored interlocked logical structure published in the open that I am aware of: thousands of objects — a theory of everything, a theory of AI, and a replicated decision framework — where every piece fits every other piece, and every claim carries the falsifier that would break it. It is not fixed. You can change what this site says by defeating what it says. Beat a claim on its own challenge surface — with a stronger argument or evidence it cannot survive — and the claim changes, the ledger records your hit, and the structure updates. Nothing here is protected from prosecution. It has only ever grown by being prosecuted. This is the final boss of recursion, meta-analysis, and parallel argument. Come at a node.

*Not medical advice. Tier-honest. Cite claim/source ids.*

The Model Context Protocol (MCP) is a way of describing a set of capabilities to a model. It is not the place those capabilities live, and it is not the thing that runs them. On this site the capabilities live in one database table — one row per capability — and MCP is one of three ways that table is shown to a model.

A projection here means exactly one thing: a view generated from a table, holding nothing of its own. Change the table and every view changes in the same instant. Delete a view and nothing is lost. Below, the plainer word surface is used wherever it reads more clearly; they mean the same thing.

The three surfaces reach the same capability catalogue. The recorded benchmark puts 6.25× between the cheapest and the dearest turn.

Evidence status

Observed marks first-party measurements or runtime receipts from the named environment. Derived marks arithmetic calculated from cited inputs. Specified marks vendor or standards documentation. Implemented and deployed name code and live-state evidence, respectively. Reproduced means the stated procedure was rerun. Externally attested marks operator reports; those reports show that an experience occurred, not that it is universal.

MCP at the wire is JSON-RPC 2.0, one of two transports, and a handful of method names

A reader who has never opened the specification can hold the whole thing in one paragraph. A client and a server exchange JSON-RPC 2.0 messages. JSON-RPC is a remote-procedure-call format: a JSON object carrying jsonrpc, method, params and id, answered by an object carrying the same id and either result or error. The specification is blunt about this: "MCP uses JSON-RPC to encode messages. JSON-RPC messages MUST be UTF-8 encoded."

Those messages travel over one of two transports. Standard input and output, for a server running as a local subprocess. Or HTTP POST, for a server running somewhere else — the specification calls the second one Streamable HTTP and requires that "Every JSON-RPC message sent from the client MUST be a new HTTP POST request to the MCP endpoint." It also states a preference: "Clients SHOULD support stdio whenever possible."

The method names that matter for a capability catalogue are four:

MethodDirectionWhat it carriesWhat this site's server returns
initializeclient → serverprotocol version, client capabilitiesprotocolVersion: "2025-06-18", capabilities: {"tools":{"listChanged":false}}, serverInfo
tools/listclient → servernothing, or a pagination cursoran array of {name, description, inputSchema} — 831 of them, measured below
tools/callclient → serverparams.name, params.arguments{content:[{type:"text",text:"…"}], isError:false}
notifications/tools/list_changedserver → clientnothingnever sent — this server declares listChanged: false

A tool definition is three fields: a name, a description in prose, and a JSON Schema for the arguments. That triple is what lands in the model's context window. Everything expensive about MCP follows from the size of that triple multiplied by the number of tools.

What MCP is not

  • Not a wire protocol. The layering claim gets used to wave away responsibility, and it is wrong. JSON-RPC is the wire protocol; MCP sits above it.
  • Not a place capabilities live. A server holds handlers. Nothing in the specification says where the list of capabilities is stored, or that it must be a hand-written list at all.
  • Not a rule about context loading. The tools specification says implementations "are free to expose tools through any interface pattern that suits their needs—the protocol itself does not mandate any specific user interaction model." Every token figure quoted below is a property of a client, not of the protocol.
  • Not a replacement for an API. It is a second face on one. The endpoint stays; MCP is a decorated index in front of it.

One recorded 891-row catalogue cost 6.25× more through its largest surface

The table holds 891 rows — 876 objects answered the live registry today, and the drift is explained under the measurements. Each row is a full capability contract: key, runner, target, documentation, input schema, authority flags. What a directory row is covers the row itself; 891 tools, zero tool schemas covers why a catalogue is better held as data than as code.

SurfaceTool definitions in the model's contextWhat the model can reachWhat the client must supportMeasured input tokens per turnMeasured cost per turnWhat breaks
Protocol onlyPOST /api/dispatch0. The 9 definitions present are the client's own built-insall 891 rowsan HTTP client. No MCP, no tool calling at all14,071$0.00456265the model must be told four endpoints once; no client UI enumerates the catalogue
Small surfaceworkers/mcp-server7 tools, whatever the catalogue sizeall 891 rows, through the dispatch toolan MCP clientnot measurednot measureda client that lists tools shows seven generic entries; discovery becomes a call, not context
Per-row MCPPOST /api/mcp831 measured today, 856 recorded831 rows, each a named toolan MCP client149,187$0.02852109prompt cost, tool-selection accuracy, and strict-schema clients rejecting the whole list
Per-row MCP, tool search on9 plus a ToolSearch toolall 891, loaded on demanda client with deferred tool loading14,109$0.00443075the deferred index does not cover every server — two filed bugs below

The arithmetic between the first and third rows: 149,187 − 14,071 = 135,116 input tokens burned per turn holding definitions the turn mostly does not use. 149,187 ÷ 14,071 = 10.6× the input tokens. $0.02852109 ÷ $0.00456265 = 6.25× the money. Across a thousand turns that gap is $23.96. The token ratio and the money ratio differ because output tokens are in both bills and the cache behaves differently; both are the recorded gateway figures, not a rate derived from one of them.

Each surface is a file, and the file states its own tool count

Per-row MCP is functions/api/mcp.js, 189 lines. Lines 118–137 are the entire projection:

js
const r = await env.DB.prepare(
  'SELECT key, type, category, content, input_schema FROM directory ' +
  'WHERE IFNULL(enabled,1)=1 AND IFNULL(planner_visible,1)=1 ' +
  'ORDER BY IFNULL(planner_rank,100), key'
).all();

One row becomes one tool: name is the row key, description is the first documentation line plus [type · category], inputSchema is the row's schema after normalisation. Line 162 is the whole tools/list handler. Lines 80–116 exist for one reason worth stating plainly: Moonshot and Kimi clients validate every schema strictly and reject the entire tool list on the first violation, so one legacy row with a required name missing from properties would blank the catalogue for that client. Claude Code tolerates both, which is how the bad schemas accumulated unnoticed.

Small surface is workers/mcp-server/src/index.ts, 138 lines, a Cloudflare McpAgent on a Durable Object. It registers seven tools, lines 19–105:

code
$ grep -A1 'this.server.tool($' workers/mcp-server/src/index.ts | grep '"'
      "d1_query",
      "kv_get",
      "kv_put",
      "list_directory",
      "dispatch",
      "oip_registry",
      "oip_invocations",

Seven, not six. An earlier record of this surface counted six by folding kv_get and kv_put into one line and omitting d1_query. The file is the authority and the file says seven. The invariant is the point either way: seven tools whether the table holds 9 rows or 9,000, because dispatch takes {key, body} and the key space is the table. All seven parameter descriptions together come to 429 characters of source.

Protocol only is functions/api/dispatch.js. No tool definitions are published anywhere. A model that can make an HTTP request resolves an intent, reads a contract, invokes it, and reads a receipt — four calls, set out in Resolve, read, invoke, receipt.

Measured today: 831 definitions occupied 434,636 bytes on the wire

Two first-party measurements, both rerunnable. MCP_TOKEN is the server's bearer token; /api/mcp accepts it in Authorization or in x-mcp-token.

Measurement 1 — count the per-row surface.

bash
curl -s -X POST https://miscsubjects.com/api/mcp \
  -H "Authorization: Bearer $MCP_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' -o tl.json \
  -w "http=%{http_code} bytes=%{size_download} time=%{time_total}s\n"

python3 -c "import json;t=json.load(open('tl.json'))['result']['tools'];print(len(t), len(json.dumps(t)))"

Three readings on 2026-07-26:

Reading (UTC)ToolsJSON bytesWhat was countedWall time
04:37:06Z833452,157Python re-serialization with spacesnot recorded
04:39:08Z831451,197Python re-serialization with spaces0.60 s
05:03:04Z831434,636exact HTTP response body0.267 s

The HTTP body contains 434,592 bytes of compact tool definitions plus the 44-byte JSON-RPC wrapper. Python's default json.dumps adds spaces after separators, which is why the command above reports 451,197 for the same 831 definitions. Both numbers are reproducible; 434,636 is the network payload.

Where the 451,197-character Python serialization goes, computed from the same file:

Component of the tool listCharactersShare
Descriptions — first doc line plus [type · category]200,75744.5%
Input schemas, after normalisation189,35442.0%
Tool names13,8623.1%
JSON structure and quoting47,22410.5%

Compact average per tool: 523 bytes. Largest single definition in the spaced Python serialization: CF_OBSERVABILITY_QUERY_WORKER_OBSERVABILITY at 6,511 bytes. By runner type the 831 split into 462 fn, 301 http, 50 flow, 18 agent.

Three counts for the same server now exist on this page — 856 recorded, 833 at 04:37, 831 at 04:39 — and each is correct for its moment. Rows get added, disabled (enabled = 0) and hidden (planner_visible = 0) while the site runs, and only enabled plus planner-visible rows are projected. A tool count taken from an MCP server is a reading, not a constant. The 891 total and the 856 projection were taken on 2026-07-25.

Measurement 2 — show that zero definitions still reaches everything.

bash
curl -s "https://miscsubjects.com/api/dispatch?registry=1" -o reg.json \
  -w "http=%{http_code} bytes=%{size_download} time=%{time_total}s\n"
python3 -c "import json;print(json.load(open('reg.json'))['count'])"

curl -s "https://miscsubjects.com/api/dispatch?ask=send%20an%20email" | head -c 400

Result at 05:03:04Z: http=200 bytes=1606794 time=0.397555s, and 876 objects. The resolver call returned {"protocol":"OIP","version":"1.2.0","kind":"ask","question":"send an email","count":12,"best":{"key":"EMAIL_SEND", …}} in 14,481 bytes — twelve candidate capabilities ranked, one recommended, none of it resident in a prompt. Nothing was registered with a model. No tool definition was loaded. All 876 objects are invokable by key.

The case for shipping an MCP surface, at its strongest

The deflationary reading — MCP is a REST API with extra steps — is usually stated by people who then keep using it. CharlieDigital, whose team built one, put the deflation and the recommendation in a single sentence: "MCP is effectively \"just another HTTP REST API\"; OAuth and everything. The key parts of the protocol is the communication shape and sequence with the client, which most SDKs abstract for you". Deploying one is no harder than deploying the API underneath it, because the SDK writes the transport.

brookst gave the sharpest rebuttal of the just-HTTP framing: "It's like saying APIs are dead because you can just use HTTP. They're not the same thing, though of course you can hand-roll the higher layer in the lower one. It's just more work, less standard, less valuable." A decorated index of features beats a bare endpoint list, and the decoration is the product.

menix argues the contract itself is the value rather than a nicety. Input and output schemas let a code-writing agent plan one precise program instead of a print-and-inspect loop, and "Tool results from programmatic calls are not added to Claude's context window, only the final code output is. They report up to 98.7% token savings in some workflows."

827a supplies the dissent every measurement below has to survive: "The idea that MCP tool definitions take up a certain number of tokens is laughable. That's an implementation detail of the agent harness." This is correct as written, and the specification agrees — nothing in MCP says a client must paste all definitions into a prompt. The measurements are of clients. They still decide the bill, because those are the clients that exist.

There is an audience argument too. oortcrate_1 prefers a bash wrapper personally and still grants the point: MCP serves non-technical teammates who want a connection that works without filing a pull request.

The case against, with the numbers the complainants actually measured

WhoWhat they measuredVerdict
moltar"Right now loading GitHub MCP takes something like 50k tokens."reduces MCP to "an API with docs"; wants progressive reveal
gertjandewilde (Apideck)"tool definitions alone burned 50,000+ tokens before the agent touched a single user message"replaced the server with a CLI at ~80 tokens; cites a 75-run comparison at 4–32× overhead
yonatangross"The main agent context burns 16.9k tokens (8.5% of 200k) loading 68 MCP tool schemas at session start. Most are never called by the main agent"publishes a per-server table; scoping and tool search were available and unused
abdlkrim-jribi"The agent injects ALL 47 tool schemas on every single request, consuming ~13,341 tokens before the user message is even sent."audits his own agent; publishes the ~4,168 / ~4,515 / ~751 / ~3,906 split
mjlee"With a handful of third party MCPs I've seen tens of thousands of tokens used before I've started anything."finds MCP beneficial anyway
0xbadcafebee"Say each tool is 150 tokens, that's 150 50, or 7500 tokens, dumped into the beginning of every session."*the balanced account — shell one-liners are more non-deterministic, so re-runs pollute context too; uses both
locknitpicker"Skills effectively turned MCPs obsolete in the vast majority of MCP applications."a progressive-disclosure CLI needs no skill file at all
noodletheworld"MCP is just \"me too\"; people want MCP to be an \"AI App Store\"; but the blunt, harsh reality is that it's basically impossible to achieve that dream"if you want an app, build an app

Two mitigations get proposed against all of this, and both have filed defects. cheema33 pre-empts the first: "And no, the tool search function recently introduced by Anthropic does not completely solve this problem." Anthropic's own documentation puts that mitigation at "over 85 percent" reduction on a five-server setup consuming "~55k tokens in definitions before Claude does any work" — real, and not total. sophiabits names the second-order cost of the other mitigation, loading servers lazily per task: "The main problem with this approach at the moment is it busts your prompt cache, because LLMs expect all tool definitions to be defined at the beginning of the context window."

Deferred loading has its own failure modes on record. In anthropics/claude-code#57033, servers added at claude.ai show Connected in /mcp and yet "Any ToolSearch query that should match a claude.ai MCP tool returns zero results". In openai/codex#24536, "codex exec can silently finish with no assistant message when an explicitly configured MCP tool is deferred behind tool_search." A silent empty turn is worse than an expensive one.

Round trips are the argument that survives bigger context windows

Token cost is a moving target. Context windows grow, caches improve, tool search lands. The structural argument does not move, and it is a different argument.

A tool call happens between completions. The model stops, the client executes, the result comes back, the model starts again. DonHopkins names the difference: "I call this \"speed of light\" as opposed to \"carrier pigeon\"." Code the model writes loops, recurses and composes inside one generation.

martinald gives the worked case — summing 150 order IDs. "With MCP the agent would have to do 150 tool calls and explode your context." One scripted loop does it in one round trip at roughly one percent of the tokens. He also notes there is no reason a harness could not expose MCP tools inside a sandboxed code environment, and that nobody does.

Two vendors have published the same finding independently. Anthropic: "This reduces the token usage from 150,000 tokens to 2,000 tokens—a time and cost saving of 98.7%." Cloudflare, on the same pattern: "With the traditional approach, the output of each tool call must feed into the LLM's neural network, just to be copied over to the inputs of the next call, wasting time, energy, and tokens. When the LLM can write code, it can skip all that, and only read back the final results it needs."

What that implies for exposing a catalogue is concrete, and it is not "abandon MCP":

  1. Expose one invoking tool that takes a key and arguments, not one tool per capability. That is what the seven-tool surface does.
  2. Make discovery a call that returns datalist_directory, or the protocol's resolver — so the catalogue is paged through rather than resident.
  3. Keep an HTTP path a code-execution sandbox can hit directly, so a loop over 150 items is one round trip instead of 150.

solarkraft supplies the honest floor under all three: every capability costs some context, because the model has to know it exists in order to invoke it. The only question is whether it costs 523 compact bytes each or one line in a search result.

notifications/tools/list_changed is in the specification, and named clients ignore it

The advertised benefit of a server-side catalogue is that adding a capability needs no client redeploy. The specification supplies the mechanism: "When the list of available tools changes, servers that declared the listChanged capability SHOULD send a notification"notifications/tools/list_changed, a JSON-RPC notification with no parameters and no reply.

Whether that works depends on the client honouring it, and three filed reports say several do not:

Client or systemFiledVerbatim
Kiro IDE — kirodotdev/Kiro#6553, closed2026-03-20"When an MCP server dynamically adds or removes tools at runtime and sends this notification per the MCP spec, Kiro IDE does not re-query tools/list, so the new tools never appear until the server is manually reconnected."
GitHub Copilot CLI — microsoft/wassette#308, open2025-09-29"Internal terminal testing shows the CLI never refreshes its tool list, unlike GitHub Copilot in VS Code which updates immediately."
MCPJungle gateway — mcpjungle/MCPJungle#260, open2026-05-15"MCPJungle caches upstream tool lists at registration time only. If an upstream server adds or removes tools later, MCPJungle's view stays stale until a manual re-registration or full restart."

The wassette report comes from a Microsoft engineer with a reproduction video, and notes the same server updates immediately in VS Code — so the defect is per-client, not per-spec.

This site's per-row server sidesteps the question by declaring the truth instead of a promise. Line 159 of functions/api/mcp.js returns capabilities: {"tools":{"listChanged":false}}. A new row is live on the protocol surface the instant it is written, and appears on the MCP surface the next time a client calls tools/list — which, for most clients, is at connect. "Add a capability without a redeploy" is true of the table and false of the client. Say the second half out loud or the sentence is a lie.

Verdict: publish MCP when the client is not yours, publish the protocol when it is

  • Do publish an MCP surface when the consumer is a client you do not control and cannot teach — Claude Desktop, Cursor, ChatGPT connectors, a colleague's IDE. There is no other way in. Publish it as a small surface: one dispatch-style tool plus a discovery tool. Never one tool per row.
  • Do publish a per-row surface only when a client must literally see named tools in its own interface, and only with that client's deferred loading switched on. Otherwise expect the bill: 149,187 input tokens and $0.02852109 per turn, measured.
  • Do not put MCP in front of your own agent when you already control the harness. The protocol surface reached all 891 capabilities at 14,071 input tokens and $0.00456265 per turn, with nine tool definitions in context — all nine of them the client's built-ins.
  • Do not treat MCP as the architecture. It is a view. The table is the thing.

What would change this verdict. A mainstream client that fetches definitions on demand rather than at connect, and honours notifications/tools/list_changed, would collapse the per-row surface's cost to roughly the protocol's and remove the reason to hand-build a small surface. Anthropic's tool search is the first move in that direction and already reaches 14,109 tokens on this catalogue — within 0.3% of the protocol-only figure. Two filed bugs, claude-code#57033 and codex#24536, say it is not yet reliable enough to depend on. When those close and the behaviour is the default rather than a flag, publish per-row and stop hand-rolling.

Publish the same catalogue three ways

Cheapest surface first, because it is also the one that works everywhere.

A. Protocol only — no server to write. Prerequisite: a capability table with a key, a runner, a target, a documentation field and an input schema (see the row contract), plus one HTTP handler that looks a key up and runs it.

  1. GET /api/dispatch returns a manifest naming the verbs and endpoint shapes. It was 17,404 bytes at 05:06:05Z.
  2. GET /api/dispatch?ask=<intent> returns ranked candidates, each with an example, an example_args and a ready run_now URL.
  3. GET /api/dispatch?key=<KEY>&format=markdown returns the exact row contract.
  4. POST /api/dispatch with {"key":"KEY","body":"args"} invokes it. Add "shape": true for a dry run that returns the fully-shaped outbound payload without firing.
  5. GET /api/dispatch?receipt=<id> returns the receipt.

Run the read-only TIME_NOW path end to end:

bash
export TERMINAL_KEY="<owner access key>"

curl -sS "https://miscsubjects.com/api/dispatch?ask=what%20time%20is%20it" \
  | jq '{count, best: .best.key}'
# {"count":12,"best":"NOW"}

curl -sS "https://miscsubjects.com/api/dispatch?key=TIME_NOW&format=markdown" \
  | sed -n '1,12p'
# begins: ## §SELF — miscsubjects capability (paste without context)

curl -sS -X POST "https://miscsubjects.com/api/dispatch" \
  -H "x-terminal-key: $TERMINAL_KEY" -H "content-type: application/json" \
  --data '{"key":"TIME_NOW","body":""}' | tee invocation.json \
  | jq '{ran, result, invocation_id: .invocation.id}'
# ran is true; result contains now, today, time, zone and iso

INVOCATION_ID="$(jq -r '.invocation.id' invocation.json)"
curl -sS "https://miscsubjects.com/api/dispatch?receipt=$INVOCATION_ID" \
  -H "x-terminal-key: $TERMINAL_KEY" | jq '{id, object_id, actor}'
# id equals $INVOCATION_ID and object_id identifies TIME_NOW

The live run at 05:06:05Z returned HTTP 200 for all four calls, resolved NOW, invoked TIME_NOW with ran: true, and read a 13,036-byte receipt. Tell the model these five endpoint shapes once, in a system prompt or skill file. Cost in tool definitions: zero.

B. Small surface — one file, seven tools. Prerequisite: an MCP SDK and somewhere to run it. On Cloudflare that is McpAgent from the agents package on a Durable Object, McpServer from @modelcontextprotocol/sdk, and zod for parameter schemas. Register dispatch with {key, body}, register one discovery tool that queries the table, expose /mcp for Streamable HTTP and /sse for the older transport, and gate both behind a bearer check. Working file: workers/mcp-server/src/index.ts.

The deployed server can be counted with the official TypeScript SDK:

bash
npm install @modelcontextprotocol/sdk
export TERMINAL_KEY="<owner access key>"

node --input-type=module <<'JS'
import {Client} from "@modelcontextprotocol/sdk/client/index.js";
import {StreamableHTTPClientTransport} from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://miscsubjects-mcp.massoumi-cyrus.workers.dev/mcp"),
  {requestInit:{headers:{authorization:`Bearer ${process.env.TERMINAL_KEY}`}}}
);
const client = new Client({name:"count-tools",version:"1"},{capabilities:{}});
await client.connect(transport);
const listed = await client.listTools();
console.log(listed.tools.map(tool => tool.name));
await client.close();
JS

Expected output, measured at 05:04:50Z: d1_query, kv_get, kv_put, list_directory, dispatch, oip_registry, oip_invocations — seven definitions totalling 2,165 compact JSON bytes. The count stays seven when the catalogue doubles because only dispatch and the discovery calls refer to catalogue keys.

C. Per-row MCP — the compatibility surface. One SELECT, one loop, one normaliser. The normaliser is the part people skip and then get bitten by: coerce every schema to a root type: "object", ensure every name in required exists in properties, give every property node a type, and flatten anyOf/oneOf/allOf to a representative branch — or a strict client rejects the entire list on the first bad row. Verify with:

bash
curl -s -X POST https://<host>/api/mcp -H "Authorization: Bearer $MCP_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | python3 -c \
  "import json,sys;print(len(json.load(sys.stdin)['result']['tools']))"

Expected output: one integer, equal to the count of enabled, planner-visible rows.

Symptom, cause, fix

SymptomCauseFix
Client shows zero tools and no errorThe whole tools/list was rejected on the first invalid schema; Moonshot and Kimi validate strictlyNormalise every schema: object root, every required name present in properties, a type on every node, no combinators. functions/api/mcp.js:44–78
401 unauthorized from /api/mcpBearer token mismatchSend Authorization: Bearer <MCP_TOKEN> or the x-mcp-token header. The check is functions/api/mcp.js:23–28
Tens of thousands of input tokens before the first user messageThe client loads every definition at connectTurn on the client's deferred tool loading, or move to a small surface
A new capability is invisible to the clientThe client ignores notifications/tools/list_changed, or the server declares listChanged: falseReconnect the client. The three filed reports above show reconnect is the reliable path
A tool exists in the table but not in tools/listThe row has enabled = 0 or planner_visible = 0Intentional. planner_visible = 0 keeps a capability callable by key while off the tool surfaces
150 items means 150 tool callsRound trips happen between completionsExpose an HTTP path a code sandbox can loop over, or one tool that takes a batch
Prompt cache hit rate collapses after adding a serverDefinitions sit at the head of the context, and changing them invalidates the cacheKeep the definition set fixed across a session; load per-task capabilities through a call, not a definition
codex exec returns an empty turnA configured server was deferred behind tool_search and never surfacedopenai/codex#24536. Pin the server as directly exposed until it closes

The comparison against staying inside the schema paradigm entirely is Tool Search and catalogue-as-data.

0
tool definitions in context in the 2026-07-25 protocol benchmark, with all 891 capabilities reachable
831
tool definitions returned by a live tools/list at 04:39:08Z on 2026-07-26
434,636
wire bytes in the live tools/list response containing 831 definitions
10.6x
input tokens per turn, per-row MCP against the protocol surface: 149,187 vs 14,071
$0.02852109
measured cost of one turn with the per-row MCP definitions attached
523
compact bytes per tool definition: 434,592 divided by 831
It's like saying APIs are dead because you can just use HTTP. They're not the same thing, though of course you can hand-roll the higher layer in the lower one. It's just more work, less standard, less valuable.— brookst, Hacker News, 2026-05-30
I call this "speed of light" as opposed to "carrier pigeon".— DonHopkins, Hacker News, 2026-02-03 — on tool calls happening between completions
Evidence · 38 sources · swipe →chain 0ec88264be0a · verify chain · provenance
1 / 38

Key evidence

15 claims · tier-ranked · API
anecdotal
The strongest case for MCP is that it is a decorated index above an API which every client already speaks, with SDKs hiding the transport, so publishing one costs about as much work as the API underneath it.
sources: s18, s19, s20, s33
anecdotal
Independent operators measured tool definitions consuming between 13,341 and more than 50,000 input tokens before any user message, on catalogues far smaller than 831 tools.
sources: s15, s16, s17, s23, s26, s28, s29, s30
system
MCP encodes its messages as JSON-RPC 2.0 and runs over one of two transports, stdio or Streamable HTTP, with every client message required to be a new HTTP POST in the second case.
sources: s1, s6, s7
system
MCP is not itself a wire protocol; JSON-RPC is the wire protocol and MCP is the layer above it.
sources: m3, s22, s7, s8
system
The same capability catalogue is reachable in full with zero tool definitions in the model's context, measured at 14,071 input tokens and $0.00456265 per turn, against 149,187 tokens and $0.02852109 for the per-row MCP projection of that same catalogue.
sources: m1, m2
system
A live tools/list against the per-row surface returned 831 tool definitions in a 434,636-byte HTTP body at 05:03:04Z on 2026-07-26, with 434,592 compact definition bytes averaging 523 per tool.
sources: m1
system
Tool counts for one MCP server are readings, not constants: the same server returned 833 and 831 two minutes apart, against 856 recorded the previous day, because rows are enabled and hidden while the site runs.
sources: m1, m4
system
A small-surface MCP server publishes a fixed number of tools regardless of catalogue size: workers/mcp-server/src/index.ts registers seven, with dispatch taking a key and arguments so the key space is the table.
sources: m4, m5, s5, s9
system
Anthropic's documentation puts a five-server setup at about 55,000 tokens of definitions before any work, and says tool search typically removes over 85 percent of that.
sources: s2
system
A tool call happens between completions, so N items means N round trips, while code the model writes loops inside a single generation.
sources: s24, s25
5 more ranked claims
system0.10
Two vendors independently published the same finding, that letting the model write code against MCP servers keeps intermediate results out of the context window, with Anthropic reporting 150,000 tokens reduced to 2,000.
Opus 5 (Claude Code)
Independent agreement between Anthropic and Cloudflare moves this from opinion to established practice.
sources: s20, s27, s3, s4
system0.10
notifications/tools/list_changed is specified, but named clients ignore it, so adding a capability without a redeploy means reconnecting or restarting the client in practice.
Opus 5 (Claude Code)
The no-redeploy promise is the main non-cost argument for a server-side catalogue, and three filed bugs show it depends on client behaviour that is not uniform.
sources: m3, s10, s11, s12, s6
system0.10
Deferred tool loading cuts the measured cost to 14,109 input tokens and $0.00443075 on this catalogue, but carries two filed defects: claude.ai-hosted servers are missing from the search index, and codex exec can end a turn silently when a configured server is deferred.
Opus 5 (Claude Code)
It is the mitigation the verdict depends on, so its failure modes decide when the verdict flips.
sources: s13, s14, s2, s31, s32
system0.10
The token cost of tool definitions is a property of the client, not of the specification, which states that implementations are free to expose tools through any interface pattern.
Opus 5 (Claude Code)
Publishing the measurements without this correction would misattribute a harness behaviour to the protocol.
sources: s21, s26, s6
system0.10
A resolver call replaces tool definitions with a query: GET /api/dispatch?ask=send%20an%20email returned 12 ranked candidates and one recommendation in 12,335 bytes, with nothing resident in a prompt.
Opus 5 (Claude Code)
It is the concrete mechanism that makes a zero-definition surface usable rather than theoretical.
sources: m2
Model review6 contributions · 1 modelExpand the recursive review layer
1 / 6
Opus 5 (Claude Code)source_hunt
sources2026-07-26 03:52
3 source(s) added · 3 sources
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: mcp-as-a-projection c2
it output
The per-row MCP projection measured 856 tools and 149,187 input tokens per turn, against 14,071 for the protocol surface.
0ee56b05860bbd15
Opus 5 (Claude Code)claim_post
claim2026-07-26 03:52
claim
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: mcp-as-a-projection c2
it output
The per-row MCP projection measured 856 tools and 149,187 input tokens per turn, against 14,071 for the protocol surface.
d47551909858c34a
Opus 5 (Claude Code)claim_post
claim2026-07-26 03:52
claim
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: mcp-as-a-projection c2
it output
The per-row MCP projection measured 856 tools and 149,187 input tokens per turn, against 14,071 for the protocol surface.
a077143cdcd18d0c
Opus 5 (Claude Code)source_hunt
sources2026-07-26 03:53
1 source(s) added · 1 sources
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: mcp-as-a-projection c4
it output
enabled and planner_visible control which surfaces a capability appears on, which is how 891 rows become 856 projected tools with no second list.
a0af57204b0d101c
Opus 5 (Claude Code)claim_post
claim2026-07-26 03:53
claim
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: mcp-as-a-projection c4
it output
enabled and planner_visible control which surfaces a capability appears on, which is how 891 rows become 856 projected tools with no second list.
17f0cbac37919943
Opus 5 (Claude Code)claim_post
claim2026-07-26 03:53
claim
inspect — what it was prompted & output
prompted with
(default writer prompt)

input: mcp-as-a-projection c4
it output
enabled and planner_visible control which surfaces a capability appears on, which is how 891 rows become 856 projected tools with no second list.
df55d6e95f8167cc
Machine verification: /api/articles/mcp-as-a-projection/contributions
Ask this article · 8 suggested prompts

Text the build (+14245134626) or WhatsApp — slug|question creates a question node. Paste evidence with ingest slug|q:NODE_ID|your paste.

What does the ledger say about this (anecdotal tier): "The strongest case for MCP is that it is a decorated index above an API which every client already speaks, with SDKs hiding the transport, s…"?
ask mcp-as-a-projection claim c7 · paste includes §SELF
What does the ledger say about this (anecdotal tier): "Independent operators measured tool definitions consuming between 13,341 and more than 50,000 input tokens before any user message, on catal…"?
ask mcp-as-a-projection claim c8 · paste includes §SELF
What does the ledger say about this (system tier): "MCP encodes its messages as JSON-RPC 2.0 and runs over one of two transports, stdio or Streamable HTTP, with every client message required t…"?
ask mcp-as-a-projection claim c1 · paste includes §SELF
What does the ledger say about this (system tier): "MCP is not itself a wire protocol; JSON-RPC is the wire protocol and MCP is the layer above it."?
ask mcp-as-a-projection claim c2 · paste includes §SELF
What does the ledger say about this (system tier): "The same capability catalogue is reachable in full with zero tool definitions in the model's context, measured at 14,071 input tokens and $0…"?
ask mcp-as-a-projection claim c3 · paste includes §SELF
What does the ledger say about this (system tier): "A live tools/list against the per-row surface returned 831 tool definitions in a 434,636-byte HTTP body at 05:03:04Z on 2026-07-26, with 434…"?
ask mcp-as-a-projection claim c4 · paste includes §SELF
For my medical situation, what can you answer from your catalogue about MCP is one view of a capability table, and the view you pick costs 6.25x — and what would you need me to tell you first?
ask mcp-as-a-projection condition gaps · paste includes §SELF
What good and bad outcomes are documented for MCP is one view of a capability table, and the view you pick costs 6.25x (studies vs anecdotes)?
ask mcp-as-a-projection good bad experiences · paste includes §SELF
mcp-as-a-projection · posted 2026-07-26 · updated 2026-07-26 · 9 prior revisions · Opus 5 (Claude Code)
Ledger API & provenance
Provenance · 6 model passes · tokens/cost unrecorded · 1 model
chain head 680b862a43bf4618
sources Opus 5 (Claude Code) · 2026-07-26 03:52 · tokens unrecorded · 160fa48f6367
claim Opus 5 (Claude Code) · 2026-07-26 03:52 · tokens unrecorded · db036cbd78a0
claim Opus 5 (Claude Code) · 2026-07-26 03:52 · tokens unrecorded · 8ca17477538f
sources Opus 5 (Claude Code) · 2026-07-26 03:53 · tokens unrecorded · 1d72f048835c
claim Opus 5 (Claude Code) · 2026-07-26 03:53 · tokens unrecorded · 9dedfc7e3a5f
claim Opus 5 (Claude Code) · 2026-07-26 03:53 · tokens unrecorded · 680b862a43bf
verify chain →
Live ledger · 3 payloads · 2 turns
recent activity · inspect
ARTICLE_CREATED automation · HTTP 200 · 2026-07-26 03:52 · t_article_vl0kdk94
AUTOMATE_FIRE dispatch · 2026-07-25 20:52 · t_jfxevlr2
AUTOMATE_FIRE dispatch · 2026-07-25 20:52 · t_jfxevlr2
view full ledger & cards →
REST + ledger
read GET /api/articles/mcp-as-a-projection · GET /api/articles/mcp-as-a-projection?format=post (the editable body)
create/replace POST /api/articles/mcp-as-a-projection · PUT /api/articles/mcp-as-a-projection (replace, keeps revision) · PATCH /api/articles/mcp-as-a-projection (merge)
delete DELETE /api/articles/mcp-as-a-projection
writes need header x-terminal-key
LLM bundle GET /api/articles/mcp-as-a-projection/bundle?format=markdown — body + claims + sources + provenance + manifest
post claim POST /api/protocol/claim · iMessage claim mcp-as-a-projection|tier|assertion
system map GET /api/articles/system-map?format=markdown — root index; every widget self-explains via §SELF / _self