---
slug: tooling-as-data
title: "Nine tool definitions reach every capability: the catalogue is a SQL table, not a prompt"
kind: essay
status: published
hash: 47588048dc6161f06915e49e2088da45e65a40a9491dccf2c78a39a5f2b5e035
created: 2026-07-26T03:52:37.503Z
updated: 2026-10-08T11:33:14.584Z
summary: "The same 891-capability catalogue measured three ways on one build: 149,187 input tokens a turn as MCP tool definitions, 14,109 with deferred tool search, 14,071 with no MCP server at all."
tags: ["tooling","oip","mcp","architecture","tool-search","context-engineering","cost"]
above: []
below: []
adjacent: []
nested: []
---
# Nine tool definitions reach every capability: the catalogue is a SQL table, not a prompt

*The same 891-capability catalogue measured three ways on one build: 149,187 input tokens a turn as MCP tool definitions, 14,109 with deferred tool search, 14,071 with no MCP server at all.*

A model's capabilities do not have to live in its context. On this build they live in a SQLite table on Cloudflare D1 called `directory` — one row per capability, reachable through one HTTP endpoint — and the model is shown nine tool definitions. Not nine capabilities. Nine definitions, and every row in the table behind them.

**Scope note:** this measures one thing — what it costs to expose *this* catalogue to a model three ways. It is not a claim that the catalogue is the whole architecture. [892 rows, 8 of them MCP](/a/the-directory-is-not-the-object-system) breaks the same `directory` table down by runner and category: eight rows are tagged `category='mcp'`; the rest are API calls, shell commands, Mac-local actions and agents. It also names the separate `articles` table and resolver, which this table and its `dispatch()` function do not cover.

The default in every agent stack is the opposite: each capability is a tool definition, each definition is JSON Schema, and the whole set is transmitted on every request. That puts catalogue size in the per-turn cost equation. This design takes it out.

## 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.

## The same catalogue, exposed three ways, measured on the same day

One build, one table, one model. Only the exposure changes. Measured 2026-07-25 on `@cf/moonshotai/kimi-k2.7-code` through Cloudflare AI Gateway, `claude-cli` 2.1.165 as the client, figures read from gateway log rows and wire captures rather than estimated.

| Exposure | What the request carries | Input tokens, one turn | Cost, that turn |
| --- | --- | --- | --- |
| One MCP tool per row (`POST /api/mcp`, `tools/list`) | 856 tool definitions | 149,187 | $0.02852109 |
| Same server, host defers the definitions (`ENABLE_TOOL_SEARCH=true`) | 9 definitions + a search tool | 14,109 | $0.00443075 |
| No MCP server attached; capabilities reached over HTTP | 9 built-in tool definitions | 14,071 | $0.00456265 |

All three rows reach the same capabilities. The first costs 10.6× the input tokens of the third for identical reach.

## The honest finding: at this size the two cheap designs cost the same

14,109 against 14,071 is a difference of 38 input tokens, 0.27%. In dollars the deferred-tool turn came out 3.0% cheaper, because the turn totals include output tokens and the two turns did not produce identical output. Anyone reading this page for a cost argument between rows two and three will not find one. **At 891 rows, deferred tool search and catalogue-as-data are the same price.**

The difference is structural, and it does not expire when the numbers do:

- Row two's cost is a function of how many definitions the model retrieves. Row three's is a function of the protocol, which is four endpoints regardless of table size.
- Row two needs the host to implement deferral. Row three needs the model to be able to make an HTTP request.

What would falsify the structural claim: a harness where deferred loading is free at any catalogue size *and* is implemented uniformly across clients. Section "Deferral is a host feature, and hosts disagree about it" is where that claim currently breaks. What would falsify the cost claim: a catalogue an order of magnitude larger, where the retrieved-definition cost of row two starts to bite while row three stays flat. That measurement has not been taken here and is not claimed.

## `defer_loading` controls context, not the request

The vendor documentation is explicit about what deferral does and does not remove, and it is the single most load-bearing fact on this page:

> `defer_loading` controls what enters the context window, not what you send in the request: You still send every tool's full definition in the `tools` array on every request, including the deferred ones. The API needs them server-side to run the search and expand `tool_reference` blocks.

— Anthropic, *Tool search tool*

So the catalogue is still enumerated, still serialised, still transmitted, every turn. It is simply not billed as context. On this build that array would be 831 tool objects and 451,197 bytes of JSON, measured live below. The client is doing that work whether or not the model reads it.

Anthropic also publishes the billing rule that makes definitions expensive in the first place: pricing counts "the total number of input tokens sent to the model (including in the `tools` parameter)". Names, descriptions and schemas are input tokens. They are re-sent every turn. They scale with how many capabilities exist.

Two independent numbers put a floor under that. Anthropic's own doc says a five-server setup — GitHub, Slack, Sentry, Grafana, Splunk — "can consume ~55k tokens in definitions before Claude does any work". The Scalekit benchmark, 5 GitHub tasks against `anthropics/anthropic-sdk-python`, Claude Sonnet 4, pre-registered hypotheses and 30 runs per arm, found the simplest task cost 1,365 tokens through a shell and 44,026 through GitHub's MCP server, and attributes it: "The difference is almost entirely schema: 43 tool definitions injected into every conversation, of which the agent uses one or two."

Divide this build's own numbers the same way. (149,187 − 14,071) ÷ 856 = **157.8 input tokens per definition**. That is close to the back-of-envelope a commenter used on Hacker News — "Say each tool is 150 tokens, that's 150 * 50, or 7500 tokens, dumped into the beginning of every session" — which means the per-definition constant is stable enough to plan against.

## One row is one capability, and this is one row

`AIG_LIST` lists the AI Gateways on a Cloudflare account. Read live with:

```
curl -s "https://miscsubjects.com/api/directory/AIG_LIST" -H "x-terminal-key: $TERMINAL_KEY"
```

Every field it carries, verbatim:

| Field | Value in `AIG_LIST` | What it does |
| --- | --- | --- |
| `key` | `AIG_LIST` | Primary key and invocation name. The only identifier a caller needs. |
| `type` | `http` | One of `fn`, `http`, `agent`, `flow`. Decides which runner executes the row. |
| `target` | `GET https://api.cloudflare.com/client/v4/accounts/$1/ai-gateway/gateways` | Where the work happens. `$1` is the first positional argument. |
| `auth` | `bearer:CLOUDFLARE_API_TOKEN` | The **name** of the environment variable holding the credential. Never the credential. |
| `content` | `# WHAT: List AI Gateways on the account`<br>`# WHEN_TO_USE: you need to aig list`<br>`# ARGS: account_id`<br>`# EX: [AIG_LIST][/AIG_LIST]` | Docstring lines then the argument template. The `#` lines are the contract a model reads; everything after them is the executable payload. |
| `category` | `null` | Grouping tag. Used to filter the registry (`?registry=1&category=…`). |
| `planner_rank` | `100` | Sort order when a planner is choosing between candidates. Lower ranks first. |
| `enabled` | `1` | `0` removes it from every projection without deleting the history. |
| `planner_visible` | `1` | `0` keeps it invocable but hides it from planners and from the MCP projection. |
| `input_schema` | `null` | Optional JSON Schema. Only consulted when the row is projected as an MCP tool. |

The field list is not folklore — it is declared in code at `/Users/owner/miscsubjects-pages/functions/_lib/dir_schema.js` lines 6–29, which is embedded in `/api/directory` responses so a client can learn the shape without prior knowledge. The docstring parser that splits `#` lines from the payload is `extractDocs`/`stripDocs` in `functions/api/dispatch.js` lines 431–450.

The full field reference, all four `type` values and what each runner does: [What a directory row is](/a/directory-row-contract).

## Four counts of the same catalogue, all of them correct

Ask the build how many capabilities it has and you get four different numbers. They are not a bug and they must not be reconciled by editing one to match another. Each is a different predicate over the same table.

Taken live at **2026-07-26T04:37:42Z**:

```
npx wrangler d1 execute loop-content-spine --remote --command \
  "SELECT COUNT(*) AS rows_total,
          SUM(CASE WHEN IFNULL(enabled,1)=1 THEN 1 ELSE 0 END) AS enabled,
          SUM(CASE WHEN IFNULL(enabled,1)=1 AND IFNULL(planner_visible,1)=1 THEN 1 ELSE 0 END) AS mcp_projected
   FROM directory;" --json
```

| Number | Surface it appears on | The predicate | Where the predicate lives |
| --- | --- | --- | --- |
| **892** | The table itself | every row | `SELECT COUNT(*) FROM directory` |
| **879** | `GET /api/dispatch?map=1` → `total` | `IFNULL(enabled,1)=1` | 13 rows are disabled and stay in the table for their history |
| **877** | `GET /api/dispatch?registry=1` → `count` | enabled, minus test-shaped keys | `TEST_ID_PATTERN` at `functions/_lib/object_contract.js:2477`, applied at `:2481-2483` |
| **832** | `POST /api/mcp` `tools/list` | `IFNULL(enabled,1)=1 AND IFNULL(planner_visible,1)=1` | `listTools()` at `functions/api/mcp.js:118-123` |

The measurement day's figures were 891 / 878 / — / 856. The table is live and other writers touch it, so a rerun returns whatever it holds at that instant; between the first and last command in this session a row was inserted by another process. That is the point of the design, not an inconvenience to it. The gap between 892 and 832 — 60 rows — is entirely disabled rows plus rows deliberately hidden from planners.

## Counting the projection, live

The MCP projection is a real server and the definition array can be weighed directly. Command:

```
curl -s -X POST https://miscsubjects.com/api/mcp \
  -H "Authorization: Bearer $MCP_TOKEN" \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

Result at 2026-07-26T04:38Z: **831 tools**, **451,197 bytes** of `tools` array, mean **543 bytes per definition**. That is the payload a client sends on every request under `defer_loading`, and the payload a model reads without it.

## A model that has never seen this build gets from question to receipt in four calls

No SDK, no client library, no prior knowledge. Four HTTP calls.

**1 — Ask in plain language.** `GET https://miscsubjects.com/api/dispatch?ask=what%20time%20is%20it` returns `count: 12`, a `best` block, and twelve ranked candidates each with a runnable URL:

```json
"best": { "key": "NOW",
          "run_now": "https://miscsubjects.com/api/dispatch?invoke=NOW&share=<TOKEN>",
          "do": "Open run_now to do it. Substitute your own text/args where the example has them." }
```

**2 — Read the contract.** `GET https://miscsubjects.com/api/dispatch?key=NOW&format=markdown` returns that capability's `_self` block: what it is, the exact POST shape, the argument template, the output contract, the auth and risk level, the troubleshooting table, and the ledger and repair addresses.

**3 — Invoke.** `POST https://miscsubjects.com/api/dispatch {"key":"NOW","body":""}`.

**4 — Take the receipt.** The response carries `proof.invocation_id` and three addresses: a credentialed forensic receipt, a keyless public confirmation, and a public brochure.

Each step with its full request and response: [The four-step loop](/a/dispatch-four-step-loop).

## The resolver is a substring scorer, and the tail of its output is noise

`answerAsk` at `functions/_lib/object_contract.js:605-640` scores every enabled row: +3 if a query term appears in the key, +1 if it appears anywhere in key, category or docstring, +1000 for a hand-pinned canonical match, −6 for a row on the demote list. Top twelve are returned.

For `?ask=what is it` the pinned answer is right and the rest is garbage. The live twelve for "what time is it":

`NOW`, `GITHUB_LIST_ISSUES`, `GITHUB_GET_ISSUE`, `GITHUB_ADD_ISSUE_COMMENT`, `GITHUB_CREATE_ISSUE`, `GITHUB_CLOSE_ISSUE`, `LOCAL_EDIT`, `LOCAL_WRITE`, `CLI_GIT`, `WRITER_AGENT`, `BLOOIO_LIST_CONTACT_IDENTITIES`, `STRIPE_INVOICE_ITEMS_LIST`

The GitHub rows match because the two-character term `is` is a substring of `issue`. There are no embeddings, no BM25, no stemming and no synonym table. A query using a word the row never uses will miss it. Anthropic's own tool search offers BM25 and regex variants for exactly this reason, and one commenter names the trade honestly: "Seems like we traded scalability for accuracy, then accuracy for scalability… but I guess maybe we've come out on top because whatever they are using for tool search is better than RAG?" On this build the mitigation is the `recommended` pin, which is a hand-maintained list, which is a real maintenance cost.

## What a row carries that a list of endpoints does not

"Put it behind an API" is not the same design. Five things live in the row that a bare endpoint list leaves to convention:

| The row carries | A bare endpoint list has | Why it matters to a model |
| --- | --- | --- |
| A docstring contract (`WHAT` / `WHEN_TO_USE` / `ARGS` / `EX`) | A path and a method | The model learns *when* to call it, not just how. |
| An auth field naming an environment variable | A credential the caller must already hold | The catalogue is publishable; the secret never appears in it. |
| A receipt per invocation, addressable | Whatever the server logged | Failure is inspectable at a URL instead of narratable. |
| A repair address (`repairs: inv_ID`) | A retry | A corrected call is linked to the failed one; lineage closes. |
| `enabled` / `planner_visible` flags | A deploy | Withdrawing a capability is an `UPDATE`. |

## The strongest objection to all of this, from someone who means it

The case against is not "MCP is fine". It is that a decorated index of features beats a bare endpoint list for a model, and that decoration is the whole product:

> 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

That is correct as stated, and this design does not contradict it. The `directory` row *is* the decorated index: the decoration is the docstring, the auth field, the schema and the flags. What is rejected is the claim that the decoration must arrive as tool definitions in the prompt. A second commenter puts the same point at the protocol level — "The idea that MCP tool definitions take up a certain number of tokens is laughable. That's an implementation detail of the agent harness." — and a third calls deferral table stakes: "Most mature harnesses do some kind of tool search and/or progressive disclosure."

Both are right that token cost is a harness property. The reply is narrow: a harness property is exactly the thing this design refuses to depend on.

## Deferral is a host feature, and hosts disagree about it

That refusal is not theoretical. Every claim below is a filed, reproducible report:

| Reported | Client | Effect |
| --- | --- | --- |
| Deferred search does not index claude.ai-hosted MCP servers | Claude Code 2.1.114 | Tools show Connected in `/mcp`, `ToolSearch` returns zero results for them |
| The deferral threshold is computed from `model.default`, not the session model | hermes-agent | A 98,304-token local model gets a threshold sized for a 256K cloud model |
| Built-in server schemas load non-deferred with no opt-out | Claude Desktop | ~3.9k tokens of first-party schemas escape deferral every session |
| A configured tool deferred behind `tool_search` yields an empty turn | codex-cli 0.133.0 | `codex exec` completes with no assistant message |
| `notifications/tools/list_changed` ignored | Kiro IDE | New tools never appear until manual reconnection |
| Same notification ignored | GitHub Copilot CLI | Tool list never refreshes; VS Code updates immediately |

The last two matter for the next section: the MCP specification's answer to adding a capability at runtime is that servers "SHOULD send a notification", `notifications/tools/list_changed`. It is a SHOULD on the server and a silent no-op in at least two shipping clients.

## The 892nd capability costs one POST and no deploy

Not an argument — a round trip run for this page.

```
curl -X POST https://miscsubjects.com/api/directory \
  -H "x-terminal-key: $TERMINAL_KEY" -H 'content-type: application/json' \
  -d '{"key":"__DOC_PROBE","type":"http",
       "target":"GET https://miscsubjects.com/api/dispatch?key=TIME_NOW",
       "category":"docs","content":"# WHAT: Probe row created to time one capability insert.\n# ARGS: none\n"}'
```

Response, `HTTP 201` in **0.437946 s**:

```json
{"ok":true,"key":"__DOC_PROBE","updated_at":"2026-07-26T04:36:08.555Z"}
```

Row count went 891 → 892. No build, no deploy, no client restart, no reconnect. Thirty-five seconds later — the directory snapshot cache is a 30-second KV entry, set in `loadDirectory()` at `functions/api/dispatch.js:413-429` — the new capability had a full self-describing contract at `?key=__DOC_PROBE`, and invoking it returned:

```json
{"ok":true,"ran":true,"proof":{"ok":true,"did":"DONE — __DOC_PROBE",
 "invocation_id":"inv_z77vqe1qi6",
 "public_receipt":"https://miscsubjects.com/receipt/inv_z77vqe1qi6"}}
```

The receipt is still public: `GET https://miscsubjects.com/api/dispatch?confirm=inv_z77vqe1qi6` returns `"confirmed": true` with no credential. The probe row was then deleted (`DELETE /api/directory/__DOC_PROBE` → `{"ok":true,"deleted":1}`); the receipt survives the row, because receipts are append-only and rows are not.

The equivalent under definitions-in-context is: publish a new definition, emit `notifications/tools/list_changed`, and hope the client re-queries. Two of the clients above do not.

## Where this design loses

Stated plainly, because a page that argues one way is not worth reading.

- **It needs a running service.** The catalogue is a table behind a Worker. If `miscsubjects.com` is down, there are zero capabilities. An MCP server on stdio keeps working with no network.
- **There is no client-side discovery.** Nothing enumerates the catalogue into a UI, a permission prompt or a tool picker. MCP clients render tool lists, ask for consent per call, and show the user what the model can reach. The specification says implementations "SHOULD" keep a human in the loop; here the human-in-the-loop surface has to be built.
- **A model that cannot make HTTP calls cannot use any of it.** Every model behind this page can. That is an assumption, not a law.
- **There is no ecosystem.** No marketplace, no registry of third-party servers, no `npx` one-liner, no standard anyone else implements. Wrapping someone else's MCP server means writing rows.
- **Retrieval quality is worse than a purpose-built search.** Substring scoring plus a hand-pinned list, versus BM25 or regex with a vendor tuning it.
- **The resolver is a single point of failure for discovery.** If `?ask=` ranks wrong, the model does not know what it missed. A full definition list has no ranking to get wrong.
- **Round trips.** Discovery is a network call before the work. One commenter frames the whole MCP-versus-in-context debate this way — "I call this 'speed of light' as opposed to 'carrier pigeon'" — and the criticism lands here too: reading a contract costs a turn that an in-context definition does not.

## The month, multiplied out

At 200 model turns per day, one seat, the measured per-turn costs above:

| Exposure | Per turn | × 200 turns/day | × 30 days |
| --- | --- | --- | --- |
| Per-row MCP, definitions in context | $0.02852109 | $5.704218 | **$171.13** |
| Deferred tool search | $0.00443075 | $0.886150 | **$26.58** |
| No MCP server, capabilities over HTTP | $0.00456265 | $0.912530 | **$27.38** |

$171.13 − $27.38 = **$143.75 a month per seat**, for exactly the same reach. Between the two cheap rows the difference is $0.79 a month, which is not a reason to choose either. Choose row three when the capability layer has to outlive one vendor's tool-calling implementation; choose row two when the host already implements deferral and the catalogue is already MCP servers.

The full dimension-by-dimension comparison: [Tool Search and catalogue-as-data, compared](/a/tool-search-vs-catalogue-as-data). What the per-row MCP projection is for and when to attach it: [MCP as a projection, not a home](/a/mcp-as-a-projection).

## Symptom, cause, fix

| Symptom | Cause | Fix |
| --- | --- | --- |
| `{"error":"unknown_key"}` from `?key=…` | The row is disabled, deleted, or the key is misspelled | `GET /api/dispatch?ask=<intent>` and use `best.key`; never guess a neighbouring key |
| A brand-new row 404s for up to 30 seconds | `loadDirectory()` caches the directory snapshot in KV for 30 s (`dispatch.js:413-429`) | Wait it out, or the write path calls `invalidateDirSnapshot(env)` (`functions/api/directory/index.js:73`) |
| `tools/list` returns fewer tools than the table has rows | `planner_visible=0` and `enabled=0` rows are excluded (`mcp.js:118-123`) | Correct behaviour. Do not edit the count to match the table |
| `POST /api/mcp` → `-32001 unauthorized` | The MCP projection takes `Authorization: Bearer <MCP_TOKEN>` or `x-mcp-token`, not the terminal key (`mcp.js:24-27`) | Send the MCP token |
| A capability runs but `proof.ok` is false | The runner returned no material output | Read the receipt and fire a repair: `{"key":"…","body":"corrected","repairs":"inv_ID"}` |
| `?ask=` returns the right row buried below GitHub rows | Two-letter query terms match as substrings (`object_contract.js:605-640`) | Query with a distinctive noun, or add the row to the canonical pin list |

## Facts

```json
{
  "converted_from": "markdown",
  "original_updated": "2026-07-27T04:29:41.904Z",
  "register": "essay",
  "category": null
}
```

## Sources

1. [Tool search tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool) — “defer_loading controls what enters the context window, not what you send in the request: You still send every tool's full definition in the tools array on every request, including the deferred ones. The API needs them server-side to run the search and expand tool_reference blocks.” (sha256 f48339eee72541e4)
2. [Tool use with Claude — Pricing](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview) — “The total number of input tokens sent to the model (including in the tools parameter)” (sha256 b607c9c9955e0d8a)
3. [Tool search tool — context bloat and selection accuracy](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool) — “A typical multiserver setup (GitHub, Slack, Sentry, Grafana, and Splunk) can consume ~55k tokens in definitions before Claude does any work. Tool search typically reduces this by over 85 percent, loading only the 3-5 tools Claude needs for a given request.” (sha256 04db741bf04004dd)
4. [Model Context Protocol specification 2025-11-25 — Server Features: Tools](https://modelcontextprotocol.io/specification/2025-11-25/server/tools) — “When the list of available tools changes, servers that declared the listChanged capability SHOULD send a notification: { "jsonrpc": "2.0", "method": "notifications/tools/list_changed" }” (sha256 ec8a28ddb2feed44)
5. [Model Context Protocol specification — User Interaction Model](https://modelcontextprotocol.io/specification/2025-11-25/server/tools) — “For trust & safety and security, there SHOULD always be a human in the loop with the ability to deny tool invocations.” (sha256 8b045f14278e43cd)
6. [modelcontextprotocol/modelcontextprotocol — docs/specification/2025-11-25/server/tools.mdx](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/server/tools.mdx) — “listChanged indicates whether the server will emit notifications when the list of available tools changes.” (sha256 b525af658ea50f62)
7. [scalekit-inc/mcp-vs-cli-benchmark — runnable harness](https://github.com/scalekit-inc/mcp-vs-cli-benchmark) — “Token overhead: MCP uses 1.3x to 80x more tokens than CLI, primarily due to tool schema overhead included in every request.” (sha256 d86c942ff253b262)
8. [MCP vs CLI: Benchmarking AI Agent Cost & Reliability](https://www.scalekit.com/blog/mcp-vs-cli-use) — “The difference is almost entirely schema: 43 tool definitions injected into every conversation, of which the agent uses one or two.” (sha256 86ad997f65b682f2)
9. [[Feature] Lazy-load MCP tool definitions to reduce token overhead](https://github.com/anomalyco/opencode/issues/35376) — “With 9 MCP servers connected (project-tools, supabase, agent-browser, chrome-devtools, playwright, memory, context7, sequential-thinking, fetch), this results in ~40,000-70,000 tokens of tool definitions loaded upfront” (sha256 dba5274df446b2f1)
10. [`GCORE_TOOLS=*` advertises ~488k tokens of tool definitions](https://github.com/G-Core/gcore-mcp-server/issues/14) — “with `GCORE_TOOLS=*` it advertises **741 tools / ~488,013 tokens** (659/tool) — that exceeds a 200K context window on its own, so the full config can't actually be used with most models.” (sha256 17fe288d0ce79f0d)
11. [Local models via opencode: slim or defer MCP tool and skills injection](https://github.com/nimbalyst/nimbalyst/issues/914) — “A one-word prompt ("Reply with exactly one word: pong") produced a request with `prompt_tokens: 154,367`” (sha256 b062162e927fe2ef)
12. [Full plugin suite's MCP tool-schema overhead makes small-context backends unusable](https://github.com/ruvnet/ruflo/issues/2726) — “`/compact` succeeded in producing a summary, but the **very next request still failed** — the non-compactable overhead (system prompt + ruflo tool schemas + plugin agent/skill listings) alone exceeded the limit.” (sha256 38e199d89ef98d32)
13. [Comment on: Apideck CLI — lower context consumption than MCP](https://news.ycombinator.com/item?id=47400262) — “We built a unified API with a large surface area and ran into a problem when building our MCP server: tool definitions alone burned 50,000+ tokens before the agent touched a single user message.” (sha256 c5dc7811fd6f0da1)
14. [Comment on: MCP is dead?](https://news.ycombinator.com/item?id=48330912) — “Say each tool is 150 tokens, that's 150 * 50, or 7500 tokens, dumped into the beginning of every session.” (sha256 07f7a9b2726eb8da)
15. [Comment on: MCP is dead?](https://news.ycombinator.com/item?id=48336021) — “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.” (sha256 2de7b95b80616ec0)
16. [Comment on: MCP is dead?](https://news.ycombinator.com/item?id=48331540) — “The idea that MCP tool definitions take up a certain number of tokens is laughable. That's an implementation detail of the agent harness.” (sha256 23037d070da563fb)
17. [Comment on: Zero-Touch OAuth for MCP](https://news.ycombinator.com/item?id=48594160) — “Most mature harnesses do some kind of tool search and/or progressive disclosure.” (sha256 927dc555f14253ea)
18. [Comment on: Claude Advanced Tool Use](https://news.ycombinator.com/item?id=46039648) — “Seems like we traded scalability for accuracy, then accuracy for scalability… but I guess maybe we've come out on top because whatever they are using for tool search is better than RAG?” (sha256 964e5a66fcecf3ec)
19. [ToolSearch does not index tools from claude.ai-hosted MCP servers](https://github.com/anthropics/claude-code/issues/57033) — “the `ToolSearch` deferred-tool discovery mechanism does NOT include them in its index. Any `ToolSearch` query that should match a claude.ai MCP tool returns zero results” (sha256 eff1fce034d8afbf)
20. [tool_search auto-gate computes its threshold from model.default](https://github.com/NousResearch/hermes-agent/issues/57520) — “For any session running a model *other than* the configured default (e.g. `--model qwen3.6-27b --provider llamacpp`, or a model switched via `/model` in the TUI), the gate is scaled to the wrong window.” (sha256 424c64f52637f7f9)
21. [Desktop: ~3.9k tokens of built-in MCP tool schemas load non-deferred](https://github.com/anthropics/claude-code/issues/76372) — “With tool search active (`ENABLE_TOOL_SEARCH` unset), third-party MCP tools correctly defer to names-only. But three Desktop built-in servers load complete schemas upfront every session” (sha256 61f8a25cf0a92429)
22. [codex exec can silently complete empty when configured MCP tools are deferred](https://github.com/openai/codex/issues/24536) — “`codex exec` can silently finish with no assistant message when an explicitly configured MCP tool is deferred behind `tool_search`.” (sha256 e1b5ba624c1129b4)
23. [Kiro IDE does not handle MCP notifications/tools/list_changed](https://github.com/kirodotdev/Kiro/issues/6553) — “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.” (sha256 66b8ff6fcc48b41a)
24. [GitHub Copilot CLI does not dynamically load tools via tools/list_changed](https://github.com/microsoft/wassette/issues/308) — “Internal terminal testing shows the CLI never refreshes its tool list, unlike GitHub Copilot in VS Code which updates immediately.” (sha256 eb5cde89e96f6db1)
25. [Comment on: Agent Skills](https://news.ycombinator.com/item?id=46878126) — “I call this "speed of light" as opposed to "carrier pigeon".” (sha256 5a5e389ee89b18b5)
26. [Comment on: When does MCP make sense vs CLI?](https://news.ycombinator.com/item?id=47209810) — “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.” (sha256 52099c72c3c160d3)
27. [Comment on: MCP is dead; long live MCP](https://news.ycombinator.com/item?id=47381282) — “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.” (sha256 bd77883c8262ce25)
28. [First-party: the same catalogue exposed three ways](https://miscsubjects.com/api/dispatch?map=1) — “856 definitions / 149,187 input tokens / $0.02852109  ·  9 + search / 14,109 / $0.00443075  ·  protocol only / 14,071 / $0.00456265” (sha256 95289bbd9ebec4c2)
29. [First-party: four counts of the same table, taken live](https://miscsubjects.com/api/dispatch?registry=1) — “rows_total 892 · enabled 879 · mcp_projected 832  (2026-07-26T04:37:42Z);  ?map=1 total 879;  ?registry=1 count 877” (sha256 7f9b992815075f4f)
30. [First-party: weighing the MCP projection with tools/list](https://miscsubjects.com/api/mcp) — “tools 831 · bytes of tools array 451,197 · mean 543 bytes per definition” (sha256 1d222fbd42ec5165)
31. [First-party: adding, invoking and removing a capability with no deploy](https://miscsubjects.com/api/dispatch?confirm=inv_z77vqe1qi6) — “{"ok":true,"key":"__DOC_PROBE","updated_at":"2026-07-26T04:36:08.555Z"} — HTTP 201 in 0.437946s; invocation inv_z77vqe1qi6 confirmed: true” (sha256 061f9f3f686a34ec)
32. [First-party: the resolver's twelve results for one query](https://miscsubjects.com/api/dispatch?ask=what%20time%20is%20it) — “NOW, GITHUB_LIST_ISSUES, GITHUB_GET_ISSUE, GITHUB_ADD_ISSUE_COMMENT, GITHUB_CREATE_ISSUE, GITHUB_CLOSE_ISSUE, LOCAL_EDIT, LOCAL_WRITE, CLI_GIT, WRITER_AGENT, BLOOIO_LIST_CONTACT_IDENTITIES, STRIPE_INVOICE_ITEMS_LIST” (sha256 3a297e82664ca24f)
33. [redacted/miscsubjects-architecture — docs/tooling/directory-row.md](https://github.com/redacted/miscsubjects-architecture/blob/main/docs/tooling/directory-row.md) — “Canonical version, with every source card and claim: https://miscsubjects.com/a/tooling-as-data” (sha256 1ca39e6fca54831f)
