feat(mcp): per-server tool filtering via include/exclude and enabled flag
Add optional config keys under each mcp_servers entry: - tools.include: whitelist, only listed tools are registered - tools.exclude: blacklist, all tools except listed are registered - enabled: false: skip server entirely, no connection attempt Backward-compatible: no config keys = all tools registered as before. Tests: TestMCPSelectiveToolLoading (4 tests), 134 passed total.
This commit is contained in:
parent
6fa197f973
commit
3198cc8fd9
2 changed files with 102 additions and 2 deletions
|
|
@ -1343,7 +1343,27 @@ async def _discover_and_register_server(name: str, config: dict) -> List[str]:
|
|||
registered_names: List[str] = []
|
||||
toolset_name = f"mcp-{name}"
|
||||
|
||||
# Selective tool loading: honour include/exclude lists from config.
|
||||
# Rules (matching issue #690 spec):
|
||||
# tools.include — whitelist: only these tool names are registered
|
||||
# tools.exclude — blacklist: all tools EXCEPT these are registered
|
||||
# include and exclude are mutually exclusive; include takes precedence
|
||||
# Neither set → register all tools (backward-compatible default)
|
||||
tools_filter = config.get("tools") or {}
|
||||
include_set = set(tools_filter.get("include") or [])
|
||||
exclude_set = set(tools_filter.get("exclude") or [])
|
||||
|
||||
def _should_register(tool_name: str) -> bool:
|
||||
if include_set:
|
||||
return tool_name in include_set
|
||||
if exclude_set:
|
||||
return tool_name not in exclude_set
|
||||
return True
|
||||
|
||||
for mcp_tool in server._tools:
|
||||
if not _should_register(mcp_tool.name):
|
||||
logger.debug("MCP server '%s': skipping tool '%s' (filtered by config)", name, mcp_tool.name)
|
||||
continue
|
||||
schema = _convert_mcp_schema(name, mcp_tool)
|
||||
tool_name_prefixed = schema["name"]
|
||||
|
||||
|
|
@ -1424,9 +1444,13 @@ def discover_mcp_tools() -> List[str]:
|
|||
logger.debug("No MCP servers configured")
|
||||
return []
|
||||
|
||||
# Only attempt servers that aren't already connected
|
||||
# Only attempt servers that aren't already connected and are enabled
|
||||
# (enabled: false skips the server entirely without removing its config)
|
||||
with _lock:
|
||||
new_servers = {k: v for k, v in servers.items() if k not in _servers}
|
||||
new_servers = {
|
||||
k: v for k, v in servers.items()
|
||||
if k not in _servers and v.get("enabled", True) is not False
|
||||
}
|
||||
|
||||
if not new_servers:
|
||||
return _existing_tool_names()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue