fix(tools): gate MCP resource and prompt registration behind enabledTools
The enabledTools allowlist was only enforced for MCP tools returned by session.list_tools(). Resources and prompts from session.list_resources() and session.list_prompts() were registered unconditionally, allowing a deny-all or restrictive enabledTools config to leak resource and prompt capabilities to the model. Now resources and prompts are only registered when allow_all_tools is true (default ["*"] wildcard). Any explicit tool restriction — including enabledTools: [] (deny-all) or a list of specific tool names — also blocks resource and prompt registration from that server. Fixes #4435
This commit is contained in:
+41
-21
@@ -797,31 +797,51 @@ async def connect_mcp_servers(
|
||||
", ".join(available_wrapped_names) or "(none)",
|
||||
)
|
||||
|
||||
try:
|
||||
resources_result = await session.list_resources()
|
||||
for resource in resources_result.resources:
|
||||
wrapper = MCPResourceWrapper(
|
||||
session, name, resource, resource_timeout=cfg.tool_timeout
|
||||
)
|
||||
registry.register(wrapper)
|
||||
registered_count += 1
|
||||
# Only register resources and prompts when no tool restriction is
|
||||
# active. enabledTools is a per-*tool* allowlist; resources and
|
||||
# prompts have no equivalent name filter, so they must be skipped
|
||||
# whenever the operator specified a tool subset. An empty list
|
||||
# (deny-all) or a list of specific tool names both indicate that
|
||||
# the operator intended to restrict capabilities — registering
|
||||
# unrestricted resource/prompt wrappers would violate that intent.
|
||||
# The default ["*"] (allow-all) means no restriction was intended.
|
||||
register_extras = allow_all_tools
|
||||
if register_extras:
|
||||
try:
|
||||
resources_result = await session.list_resources()
|
||||
for resource in resources_result.resources:
|
||||
wrapper = MCPResourceWrapper(
|
||||
session, name, resource, resource_timeout=cfg.tool_timeout
|
||||
)
|
||||
registry.register(wrapper)
|
||||
registered_count += 1
|
||||
logger.debug(
|
||||
"MCP: registered resource '{}' from server '{}'",
|
||||
wrapper.name,
|
||||
name,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug(
|
||||
"MCP: registered resource '{}' from server '{}'", wrapper.name, name
|
||||
"MCP server '{}': resources not supported or failed: {}", name, e
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug("MCP server '{}': resources not supported or failed: {}", name, e)
|
||||
|
||||
try:
|
||||
prompts_result = await session.list_prompts()
|
||||
for prompt in prompts_result.prompts:
|
||||
wrapper = MCPPromptWrapper(
|
||||
session, name, prompt, prompt_timeout=cfg.tool_timeout
|
||||
try:
|
||||
prompts_result = await session.list_prompts()
|
||||
for prompt in prompts_result.prompts:
|
||||
wrapper = MCPPromptWrapper(
|
||||
session, name, prompt, prompt_timeout=cfg.tool_timeout
|
||||
)
|
||||
registry.register(wrapper)
|
||||
registered_count += 1
|
||||
logger.debug(
|
||||
"MCP: registered prompt '{}' from server '{}'",
|
||||
wrapper.name,
|
||||
name,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug(
|
||||
"MCP server '{}': prompts not supported or failed: {}", name, e
|
||||
)
|
||||
registry.register(wrapper)
|
||||
registered_count += 1
|
||||
logger.debug("MCP: registered prompt '{}' from server '{}'", wrapper.name, name)
|
||||
except Exception as e:
|
||||
logger.debug("MCP server '{}': prompts not supported or failed: {}", name, e)
|
||||
|
||||
logger.info(
|
||||
"MCP server '{}': connected, {} capabilities registered", name, registered_count
|
||||
|
||||
Reference in New Issue
Block a user