Problem
Today, the only way to restrict which tools from a given backend are exposed is through the global ACL (~/.config/mcp/acl.json), which operates on identity + role at the proxy layer. There is no way to declare, at the server definition itself, which tools should be visible/callable regardless of who is calling.
This leaves real gaps:
- Blast radius of a misbehaving server. If a backend exposes dangerous tools (e.g.
delete_all, execute_shell) alongside safe ones, the operator has to either remove the whole server or write ACL rules for every identity. There is no per-server "never expose this tool" switch.
- Noise in
mcp <server> --list and in mcp serve's aggregated tool list. Servers like filesystem, kubernetes, slack expose dozens of tools; most users only use a handful. There is no way to say "this server only exposes tools X, Y, Z" in the config.
- Principle of least privilege at the config layer. ACL is role-based and lives separately. For a shared workstation, a solo developer, or a CLI-only workflow (no proxy, no identities), users currently cannot scope down a server without editing ACL files designed for a different purpose.
- Discoverability. A tool hidden by ACL still surfaces in
--list (the ACL is enforced on call, not on listing, depending on context). A config-level filter should make the tool disappear everywhere — --list, --info, proxy aggregation, and call — for every caller.
Desired outcome
Each server entry in servers.json can carry an allowedTools (inclusive list) or a blockedTools (exclusive list). The two are mutually exclusive per server. Filtered tools are:
- Absent from
mcp <server> --list and mcp <server> --info.
- Absent from the aggregated tool list served by
mcp serve.
- Rejected with a clear error when called directly (
tool not available on this server).
This is a static, config-level filter — orthogonal to ACL. ACL continues to enforce identity/role policy; this setting just shapes what the server exposes in the first place.
Out of scope
- Wildcard/regex semantics, default-deny vs default-allow for unknown tools, and interaction with ACL precedence — to be decided in design.
- Runtime reconfiguration / hot reload.
Related
Prior art
Problem
Today, the only way to restrict which tools from a given backend are exposed is through the global ACL (
~/.config/mcp/acl.json), which operates on identity + role at the proxy layer. There is no way to declare, at the server definition itself, which tools should be visible/callable regardless of who is calling.This leaves real gaps:
delete_all,execute_shell) alongside safe ones, the operator has to either remove the whole server or write ACL rules for every identity. There is no per-server "never expose this tool" switch.mcp <server> --listand inmcp serve's aggregated tool list. Servers likefilesystem,kubernetes,slackexpose dozens of tools; most users only use a handful. There is no way to say "this server only exposes tools X, Y, Z" in the config.--list(the ACL is enforced on call, not on listing, depending on context). A config-level filter should make the tool disappear everywhere —--list,--info, proxy aggregation, and call — for every caller.Desired outcome
Each server entry in
servers.jsoncan carry anallowedTools(inclusive list) or ablockedTools(exclusive list). The two are mutually exclusive per server. Filtered tools are:mcp <server> --listandmcp <server> --info.mcp serve.tool not available on this server).This is a static, config-level filter — orthogonal to ACL. ACL continues to enforce identity/role policy; this setting just shapes what the server exposes in the first place.
Out of scope
Related
--list(ad-hoc filter, not persistent)Prior art
mcporter0.9.0 ships this asallowedTools/blockedToolsin server definitions. See: https://github.com/steipete/mcporter