Problem
vMCP tool filtering (aggregation.tools, filter, excludeAll, excludeAllTools) is enforced on the Legacy path but not on the Modern one. A Modern client that knows the name of a filtered-out tool can call it successfully.
Why the paths differ
Aggregation produces two things: the advertised tool list (filtered) and an internal routing table (unfiltered, because composite tools are built on hidden backend tools).
Legacy registers one handler per advertised tool, so a filtered tool has no handler and the call is rejected as unknown before it goes anywhere. Registration is the gate.
Modern is stateless and has no registration step — it takes the tool name off the request and routes it against the unfiltered table. Nothing narrows it.
Why it matters
Filtering is understood as an access control boundary — #6073 uses a filtered vMCP to constrain unsupervised agents. That holds today on Legacy and silently stops holding for Modern clients, which is the worse failure mode: the same config quietly means something different depending on which revision a client speaks.
Fix
Refuse to route a Modern call for a tool that isn't in the advertised set, so both paths enforce filtering identically.
Composite tools are unaffected — they route through their own path, not the client call path.
Relates to #6073, #3493, #3499.
Problem
vMCP tool filtering (
aggregation.tools,filter,excludeAll,excludeAllTools) is enforced on the Legacy path but not on the Modern one. A Modern client that knows the name of a filtered-out tool can call it successfully.Why the paths differ
Aggregation produces two things: the advertised tool list (filtered) and an internal routing table (unfiltered, because composite tools are built on hidden backend tools).
Legacy registers one handler per advertised tool, so a filtered tool has no handler and the call is rejected as unknown before it goes anywhere. Registration is the gate.
Modern is stateless and has no registration step — it takes the tool name off the request and routes it against the unfiltered table. Nothing narrows it.
Why it matters
Filtering is understood as an access control boundary — #6073 uses a filtered vMCP to constrain unsupervised agents. That holds today on Legacy and silently stops holding for Modern clients, which is the worse failure mode: the same config quietly means something different depending on which revision a client speaks.
Fix
Refuse to route a Modern call for a tool that isn't in the advertised set, so both paths enforce filtering identically.
Composite tools are unaffected — they route through their own path, not the client call path.
Relates to #6073, #3493, #3499.