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.
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.
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".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.
Two controls put you in charge of the diet.