Reflection: Tool Design Patterns Worth Borrowing

  1. buildTool() + defaults = fail-closed safety baseline: New tools default to no-concurrency, no-readonly, allow permission — this combination sounds permissive, but combined with the outer permission rules system (see Section B), the actual effect is: tool developers don't need to repeat common security checks, only declare differences, while permissions are handled centrally.

  2. Render layer built into the tool interface: Each tool carries its own UI render methods, meaning adding a new tool produces a complete product experience — no need to separately maintain a "tool ID → render component" mapping table. Tools are self-contained units.

  3. BashTool uses AST parsing, not string matching: The most dangerous tool gets the strictest checking, preventing rule bypass. This is a tradeoff between security and usability — string matching is faster, but it's easy to write commands that bypass it.

  4. REPL mode is internal-only: Batching tool calls reduces API round-trips and improves internal development efficiency; but SDK users need precise control over each individual tool call, so REPL mode is explicitly excluded from SDK entry points. This reflects the balance between internal efficiency and external API semantics.

  5. Tool lazy-loading = token economics: When the tool count grows to dozens, the cost of loading everything upfront becomes non-trivial. shouldDefer / alwaysLoad is the infrastructure for tool count growth, laying the groundwork for integrating more MCP tools in the future.