FULL_TOOLS = [ "Read", "Edit", "Write", "Bash", "Glob", "Grep", "AskUserQuestion", "WebSearch", "WebFetch", "NotebookEdit", "TodoWrite", "EnterPlanMode", "ExitPlanMode", "EnterWorktree", "TaskOutput", "TaskStop", "CronCreate", "CronList", "CronDelete", "InvokeAgent", "Agent", # ToolSearch is the loader the CLI uses to expose deferred tool schemas # on demand. Must be in the allowedTools whitelist or the model can't # call it, which means none of the deferred extended tools become # reachable even when the CLI advertises them in the system prompt. "ToolSearch", ] def _get_denied_tool_names(tool) -> set[str]: """Return the set of MCP sub-tool names whose permission is 'deny'.""" return { key for key, value in tool.tool_permissions.items() if not key.startswith("_") and value == "deny" } def _get_all_known_tool_names(tool) -> set[str]: """Return all known sub-tool names for an MCP tool (from _tool_descriptions).""" return set(tool.tool_permissions.get("_tool_descriptions", {}).keys()) def _is_fully_denied(tool) -> bool: """True when every known sub-tool on this MCP server is set to 'deny'.""" known = _get_all_known_tool_names(tool) if not known: return False return known <= _get_denied_tool_names(tool)