Repository navigation
[MCP Bundle] Allow grouping tools into servers by tag, not just by namespace #2426
Description
Activity
- addedMCP BundleIssues & PRs about the MCP SDK integration bundleIssues & PRs about the MCP SDK integration bundleFeatureNew featureNew feature
on Aug 21, 2026 I think maybe we should just allow to define a service that returns the list of tools per server? Then I can implement my own one filtering on whatever I need? Whether that's an array key based on
$metaof everyMcpToolinstance or some other custom registry, doesn't matter then.@Toflar good idea, and it sidesteps the tag question: no naming convention to invent, no collision rule to define.
One thing to settle first, so we do not have to redo it: filtering happens at compile time today.
McpPasshands each server a service locator with only its own references, which is also whatdebug:mcpand the typo check live on. A runtime provider would cost us those.So I would ask your service at container build, passing the service id, the class and the attribute metadata, and make the current string patterns the default implementation of that same interface instead of a second code path.
Would that cover your case, or do you actually need to decide at runtime?
A runtime provider would cost us those.
To be honest, I think we will need that anyway? As soon as tools become permission-aware as not every user should get the same tools, we have exactly that?
@Toflar fair point, and yes, we needed exactly that already. we built it at sulu as a plain
RegistryInterfacedecorator: https://github.com/sulu/SuluMcpBundle/blob/1.0/src/Infrastructure/Mcp/FilteredRegistry.phpso the permission case works today without any bundle change. the registry is per server (
mcp.server.<name>.registry), so you can decorate just the one you want.that said, i agree it could be more comfortable. our decorator is ~250 lines and almost all of it is proxying
RegistryInterfacejust to filter one list, so a smaller hook for that would be welcome.two things we ran into, in case they help here:
- listing and calling need different rules.
getTools()filters by what the current user may see,getTool()deliberately does not, so calling a hidden tool gives a permission denial instead of a fabricated "not found". - filtering at registration was not enough on its own. runtime attribute discovery re-adds what we pruned at compile time, so
setDiscoveryState()needs the same treatment.
which is why i would still keep the two apart: compile time decides which tools a server has, and that is what keeps
debug:mcpand the typo check meaningful, runtime decides which of those this user sees. the provider idea would cover the first, your permission case is the second and already has a home.- listing and calling need different rules.
compile time decides which tools a server has, and that is what keeps
debug:mcpand the typo check meaningful, runtime decides which of those this user sees.I agree. So tagging a tool to say "this server only has the tools with tag
foobar" still seems the way to go for me then. Otherwise platforms like Sulu and Contao etc. cannot group tools from all sorts of namespaces for e.g. the admin backend vs. the frontend etc.Reacted by Johannes Wachter
Follow-up to #2412, which introduced per-server element filtering in the MCP bundle. Raised by @Toflar there, parked so the PR could land.
The use case
Filtering currently takes service ids, FQCNs, namespace prefixes and
*:That works when the tools of one server happen to share a namespace. It does not when they are spread across several vendor namespaces, which is the normal case as soon as bundles start shipping tools. @Toflar's proposal is to group by tag instead:
Beyond namespaces, this would let an application tag a third-party tool into a server from a compiler pass, without touching the vendor code.
The open question
@OskarStark's objection is the thing to solve first: nothing makes a tag unique across vendors.
foofrom two bundles is the same string, whereas an FQCN or a namespace prefix is unambiguous by construction. A tag design therefore needs a naming convention, or a scoping rule, before it is safe to expose.Worth deciding:
acme/public) or scoped to the declaring bundle.Why it can wait
The config node is a heterogeneous scalar list, so a tag form can be added additively later, for example as
#fooortag:foo, without changing the meaning of any existing value and without a second BC break. Nothing in #2412 forecloses this.