MoriMori
Mori

Tool catalog & deferral

Mori carries 154 native tools plus everything you connect over MCP — but by default the model sees a sharp core set and pulls the rest from a searchable catalog on demand. Same permissions, same audit log, a fraction of the tokens.

Why the schema goes on a diet

Every tool a model can call rides along as a schema in every request — name, description, and full parameter definitions. With 154 native tools plus connected MCP servers, that is more than 20,000 tokens of schema per request, paid again on every turn of every task, before a single word of conversation. Cost is only half the problem: a 154-item menu also diffuses tool choice — attention is a budget too.

So by default Mori defers most of the catalog. The visible schema carries a core set of 65 tools — files, terminal and dev servers, web and research, element-first computer control, the everyday assistant cluster (music, calendar, reminders, clipboard), memory and continuity, delegation and deliverables — plus three bridge tools that reach everything else. That is 68 schemas instead of 154-plus: a ~56% cut, on the order of 9,000 tokens saved on every request, and a shorter menu that sharpens the choice among the tools that remain.

The three bridges

  • tool_search — searches the entire permitted catalog, native and MCP alike, by capability ("calendar event", "ocr image", "zip folder"). Matching is BM25-style over each tool's name, description, and parameter names, with rarer terms weighted higher. Results come back as names plus descriptions, ready for the next step.
  • tool_describe — returns the complete parameter schema (JSON Schema) of one named tool, so arguments are written against the real contract rather than a guess.
  • tool_call — runs any catalog tool by name with JSON arguments. It is a pass-through, not a side door — see the next section.

The catalog behind the bridges is rebuilt from the live tool definitions on every request. It includes MCP tools the moment a server connects, and it can never go stale or drift from what actually runs.

tool_search { query: "zip folder" }
→ Tools matching "zip folder":
  • create_zip — … (params: …)

tool_describe { name: "create_zip" }
→ create_zip: full parameter schema (JSON Schema)

tool_call { name: "create_zip", args_json: "{ … }" }
→ executes create_zip through the same permission checks and
  approval gates as a direct call — and the activity log
  shows "create_zip", not "tool_call".

Same permissions, same log

tool_call grants nothing a direct call would not. It recurses into the exact same dispatcher as every direct tool call, so the entire enforcement stack fires unchanged: permission checks against your settings, approval and confirmation gates, diff cards for file edits, and the activity log. The log records the real tool's name — the audit trail shows what actually ran, never a wall of tool_call entries.

A few edges are closed deliberately: the bridges cannot call themselves, a tool your settings do not permit is refused at the bridge exactly as it would be anywhere else, and arguments that arrive as invalid JSON are bounced back with instructions to re-check the schema — nothing executes on a half-parsed call.

Pinning, and turning deferral off

Two controls put you in charge of the diet.

  • Pinning. Pin a tool on the Tools page and it is un-deferred: it always rides in the visible schema, sorted ahead of everything else (position is attention), and the turn context names your pinned tools as preferred. Pin what you reach for constantly; the bridges cover the rest.
  • The switch. A settings toggle turns deferral off entirely, sending every schema on every request — useful for debugging, or for models that handle large tool menus well. Deferral is on by default.