Skip to content

feat(macros): reject an empty #[tool_router] - #1233

Open
DaleSeo wants to merge 1 commit into
mainfrom
DaleSeo/tool_router-builds-an-empty-router-without-compl
Open

feat(macros): reject an empty #[tool_router]#1233
DaleSeo wants to merge 1 commit into
mainfrom
DaleSeo/tool_router-builds-an-empty-router-without-compl

Conversation

@DaleSeo

@DaleSeo DaleSeo commented Aug 31, 2026

Copy link
Copy Markdown
Member

Closes #1174.

Motivation and Context

An impl annotated with #[tool_router] that had no directly visible #[tool] functions compiled without any diagnostics and produced a router with zero tools. The server advertised an empty catalogue, and the problem only showed up on the other side of the connection, when a model found no tools.

#[tool_router] now rejects an impl with no #[tool] functions instead of quietly building a router that serves nothing. Use #[tool_router(allow_empty)] to opt out.

How Has This Been Tested?

Add tests

error: `#[tool_router]` found no `#[tool]` fn in this impl block, so `Self::tool_router()` would serve no tools
       note: a `macro_rules!` invocation inside the impl block is not expanded before this
             attribute runs, so any `#[tool]` fn it generates is invisible here; let the
             `macro_rules!` emit the whole `#[tool_router] impl` instead
       note: use `#[tool_router(allow_empty)]` if an empty router is intended
  --> src/probe.rs:15:6
   |
15 | impl Probe {
   |      ^^^^^

Breaking Changes

There is no API change, but an impl block annotated with #[tool_router] no longer compiles if it doesn't contain any #[tool] functions. This is intended because an impl with no tools is almost always a mistake.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@github-actions github-actions Bot added T-test Testing related changes T-macros Macro changes labels Aug 31, 2026
@DaleSeo DaleSeo self-assigned this Aug 31, 2026
@DaleSeo
DaleSeo force-pushed the DaleSeo/tool_router-builds-an-empty-router-without-compl branch from d595603 to da16056 Compare September 1, 2026 12:37
@DaleSeo
DaleSeo force-pushed the DaleSeo/tool_router-builds-an-empty-router-without-compl branch from da16056 to a106576 Compare September 1, 2026 12:39
@DaleSeo DaleSeo changed the title feat(macros): warn when #[tool_router] collects no tools feat(macros): reject an empty #[tool_router] Sep 1, 2026
@DaleSeo
DaleSeo marked this pull request as ready for review September 1, 2026 23:49
@DaleSeo
DaleSeo requested a review from a team as a code owner September 1, 2026 23:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-macros Macro changes T-test Testing related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

#[tool_router] builds an empty router without complaining when the impl has no directly-visible #[tool] fn

1 participant