Skip to main content
Glama

scan_dependencies

Analyze code dependencies to identify required functions and imports before making edits, preventing errors in JavaScript, TypeScript, HTML, and Python projects.

Instructions

Scans code for dependencies. Supports JS, TS, HTML, Python.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
codeYes
target_functionYes
languageNoauto
ignore_customNo

Implementation Reference

  • The primary handler function for the 'scan_dependencies' tool. Decorated with @mcp.tool() for registration. Scans code snippets for dependencies in Python (AST), JS/TS/HTML (Tree-sitter), returns formatted analysis with suggested index.
    def scan_dependencies(
        code: str, 
        target_function: str, 
        language: str = "auto", 
        ignore_custom: Union[List[str], str, None] = None
    ) -> str:
        """
        Scans code for dependencies. Supports JS, TS, HTML, Python.
        """
        try:
            if parser_js is None: return "CRITICAL ERROR: Tree-sitter parsers failed to initialize."
            
            # СБРОС СОСТОЯНИЯ ПРИ НОВОМ СКАНИРОВАНИИ
            # Это важно: если ИИ начал сканировать заново, он теряет право на правку
            APPROVAL_STATE[target_function] = "NONE"
            
            normalized_ignore = []
            if isinstance(ignore_custom, list):
                normalized_ignore = ignore_custom
            elif isinstance(ignore_custom, str):
                normalized_ignore = [ignore_custom]
            
            lang_lower = language.lower()
            
            # --- PYTHON ---
            if lang_lower == "python" or lang_lower == "py":
                deps, logs = _extract_python_dependencies(code, target_function, normalized_ignore)
                sorted_deps = sorted(list(deps))
                return f"""
                [ACCESS REVOKED] Python Analysis for '{target_function}':
                --------------------------------
                Found Dependencies: {', '.join(sorted_deps) if sorted_deps else 'None'}
                SUGGESTED INDEX: {target_function + ("_" + "_".join(sorted_deps) if sorted_deps else "")}
                
                DEBUG INFO:
                {chr(10).join(logs[:15])}
                """
    
            # --- HTML ---
            if lang_lower == "html":
                if not parser_html: return "Error: HTML parser not initialized."
                tree = parser_html.parse(bytes(code, "utf8"))
                deps, logs = _extract_html_dependencies(tree)
                sorted_deps = sorted(list(deps))
                return f"""
                [ACCESS REVOKED] HTML Analysis for '{target_function}':
                --------------------------------
                Found Dependencies: {', '.join(sorted_deps) if sorted_deps else 'None'}
                DEBUG INFO:
                {chr(10).join(logs)}
                """
    
            # --- JS / TS ---
            selected_parser = parser_js
            logs_prefix = "JavaScript"
    
            if lang_lower == "auto":
                if "def " in code or "import " in code or "class " in code:
                     try:
                         ast.parse(code)
                         deps, logs = _extract_python_dependencies(code, target_function, normalized_ignore)
                         sorted_deps = sorted(list(deps))
                         return f"""
                         [ACCESS REVOKED] Auto-Detected Python Analysis for '{target_function}':
                         --------------------------------
                         Found Dependencies: {', '.join(sorted_deps) if sorted_deps else 'None'}
                         SUGGESTED INDEX: {target_function + ("_" + "_".join(sorted_deps) if sorted_deps else "")}
                         """
                     except:
                         pass
    
                tree_js = parser_js.parse(bytes(code, "utf8"))
                js_errors = has_syntax_errors(tree_js)
                tree_ts = parser_ts.parse(bytes(code, "utf8"))
                ts_errors = has_syntax_errors(tree_ts)
                
                if js_errors and not ts_errors:
                    return """
                    🛑 AMBIGUITY DETECTED
                    ---------------------
                    The code looks like TypeScript. Please ASK THE USER: "Is this JavaScript or TypeScript?"
                    """
                elif not js_errors:
                    selected_parser = parser_js
                    logs_prefix = "Auto-Detected JS"
                else:
                    selected_parser = parser_ts
                    logs_prefix = "Auto-Detected TS (Fallback)"
                    
            elif lang_lower in ["ts", "typescript", "tsx"]:
                selected_parser = parser_ts
                logs_prefix = "TypeScript"
            elif lang_lower == "python":
                return "Python support via AST module is available in v4.3 if needed."
    
            tree_raw = selected_parser.parse(bytes(code, "utf8"))
            deps, logs = _extract_dependencies_from_tree(tree_raw, target_function, normalized_ignore)
            
            used_wrapper = False
            if not deps:
                logs.append("--- Attempting Auto-Wrapper ---")
                wrapped_code = f"class AutoWrapper {{ {code} }}"
                tree_wrapped = selected_parser.parse(bytes(wrapped_code, "utf8"))
                deps_wrapped, logs_wrapped = _extract_dependencies_from_tree(tree_wrapped, target_function, normalized_ignore)
                if deps_wrapped:
                    deps = deps_wrapped
                    logs.extend(logs_wrapped)
                    used_wrapper = True
    
            sorted_deps = sorted(list(deps))
            index_str = target_function + ("_" + "_".join(sorted_deps) if sorted_deps else "")
            
            debug_output = "\n    ".join(logs[:15])
            
            return f"""
            [ACCESS REVOKED] {logs_prefix} Analysis for '{target_function}':
            --------------------------------
            Found Dependencies: {', '.join(sorted_deps) if sorted_deps else 'None'}
            SUGGESTED INDEX: {index_str}
            
            DEBUG INFO:
            Wrapper Used: {used_wrapper}
            Logs:
            {debug_output}
            ...
            """
        except Exception as e:
            return f"INTERNAL SERVER ERROR during scanning: {str(e)}\nTraceback: {traceback.format_exc()}"
  • Helper function to extract dependencies from Python code using AST, ignoring builtins and custom list.
    def _extract_python_dependencies(code: str, target_name: str, ignore_custom: Optional[List[str]] = None) -> Tuple[Set[str], List[str]]:
        dependencies = set()
        logs = []
        try:
            tree = ast.parse(code)
        except SyntaxError as e:
            return set(), [f"Python Syntax Error: {e}"]
    
        target_node = None
        for node in ast.walk(tree):
            if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
                if node.name == target_name:
                    target_node = node
                    break
        
        if target_node:
            logs.append(f"✅ Found Python target: {type(target_node).__name__}")
        else:
            logs.append("❌ Target node NOT found. Scanning entire snippet.")
            target_node = tree
    
        IGNORE_PYTHON = {
            "print", "len", "str", "int", "float", "bool", "list", "dict", "set", "tuple",
            "range", "enumerate", "zip", "map", "filter", "sum", "min", "max", "abs",
            "isinstance", "issubclass", "type", "super", "getattr", "setattr", "hasattr",
            "open", "dir", "id", "input", "repr", "round", "sorted", "reversed",
            "__init__", "__str__", "__repr__", "self"
        }
        if ignore_custom:
            IGNORE_PYTHON.update(ignore_custom)
    
        for node in ast.walk(target_node):
            call_name = None
            if isinstance(node, ast.Call):
                if isinstance(node.func, ast.Name):
                    call_name = node.func.id
                elif isinstance(node.func, ast.Attribute):
                    call_name = node.func.attr
                    if isinstance(node.func.value, ast.Name) and node.func.value.id == 'self':
                        logs.append(f"Found self call: {call_name}")
            
            if call_name:
                if call_name not in IGNORE_PYTHON and call_name != target_name:
                    dependencies.add(call_name)
    
        return dependencies, logs
  • Core helper for extracting dependencies from JS/TS Tree-sitter parse trees, scans call expressions and member accesses.
    def _extract_dependencies_from_tree(tree, target_name: str, ignore_custom: Optional[List[str]] = None) -> Tuple[Set[str], List[str]]:
        if not tree: return set(), ["Error: Tree is None"]
        root_node = tree.root_node
        dependencies = set()
        logs = []
    
        def find_target_node(node, name):
            if node.type == 'class_declaration':
                name_node = node.child_by_field_name('name')
                if name_node and name_node.text.decode('utf8') == name: return node
            if node.type == 'function_declaration':
                name_node = node.child_by_field_name('name')
                if name_node and name_node.text.decode('utf8') == name: return node
            elif node.type == 'method_definition':
                name_node = node.child_by_field_name('name')
                if name_node and name_node.text.decode('utf8') == name: return node.child_by_field_name('body')
            elif node.type == 'lexical_declaration':
                for i in range(node.child_count):
                    child = node.child(i)
                    if child.type == 'variable_declarator':
                        name_node = child.child_by_field_name('name')
                        if name_node and name_node.text.decode('utf8') == name: return child.child_by_field_name('value')
            for i in range(node.child_count):
                res = find_target_node(node.child(i), name)
                if res: return res
            return None
    
        target_node = find_target_node(root_node, target_name)
        
        if target_node:
            logs.append(f"✅ Found target node type: {target_node.type}")
        else:
            logs.append("❌ Target node NOT found. Scanning root.")
            target_node = root_node
    
        IGNORE_LIST = {
            "console", "Math", "JSON", "Date", "Object", "Array", "Promise", "Error",
            "parseInt", "parseFloat", "setTimeout", "setInterval", "alert", "confirm",
            "require", "window", "document", "history", "navigator", "location"
        }
        
        IGNORE_METHODS = {
            "log", "error", "warn", "info", "debug",
            "push", "pop", "shift", "unshift", "splice", "slice", "join", "split",
            "map", "filter", "reduce", "forEach", "find", "some", "every",
            "toString", "toFixed", "replace", "replaceAll", "trim",
            "querySelector", "querySelectorAll", "getElementById", "addEventListener",
            "remove", "add", "has", "get", "set", "keys", "values", "entries",
            "now", "abs", "round", "floor", "ceil", "min", "max", "random",
            "then", "catch", "finally", "length", "subscribe", "unsubscribe"
        }
    
        if ignore_custom:
            IGNORE_LIST.update(ignore_custom)
            IGNORE_METHODS.update(ignore_custom)
    
        def find_calls(node):
            if node.type == 'call_expression':
                func_node = node.child_by_field_name('function')
                call_name = None
                
                if func_node.type == 'identifier':
                    call_name = func_node.text.decode('utf8')
                elif func_node.type == 'member_expression':
                    prop_node = func_node.child_by_field_name('property')
                    obj_node = func_node.child_by_field_name('object')
                    if prop_node:
                        method_name = prop_node.text.decode('utf8')
                        obj_name = obj_node.text.decode('utf8') if obj_node else "unknown"
                        if (obj_node.type == 'this') or (obj_name == 'this'):
                            call_name = method_name
                        elif method_name not in IGNORE_METHODS:
                            call_name = method_name
                
                if call_name:
                    if call_name not in IGNORE_LIST and call_name != target_name:
                        dependencies.add(call_name)
                    else:
                        # logs.append(f"Ignored: {call_name}")
                        pass
    
            for i in range(node.child_count):
                find_calls(node.child(i))
    
        find_calls(target_node)
        return dependencies, logs
  • Helper to extract dependencies from HTML Tree-sitter tree, focusing on script src and event handlers.
    def _extract_html_dependencies(tree) -> Tuple[Set[str], List[str]]:
        if not tree: return set(), ["Error: HTML Tree is None"]
        root_node = tree.root_node
        dependencies = set()
        logs = []
        
        logs.append("Scanning HTML structure...")
    
        def traverse(node):
            if node.type == 'attribute':
                attr_name = None
                attr_value = None
                
                for i in range(node.child_count):
                    child = node.child(i)
                    if child.type == 'attribute_name':
                        attr_name = child.text.decode('utf8')
                    elif child.type == 'quoted_attribute_value' or child.type == 'attribute_value':
                        attr_value = child.text.decode('utf8').strip('"\'')
    
                if attr_name and attr_value:
                    if attr_name == 'src':
                        parent = node.parent
                        if parent and (parent.type == 'script_start_tag' or parent.type == 'script_element'):
                            dependencies.add(f"FILE: {attr_value}")
                            logs.append(f"Found script: {attr_value}")
                    
                    elif attr_name.startswith('on'):
                        func_name = attr_value.split('(')[0].strip()
                        if func_name:
                            dependencies.add(f"EVENT: {func_name}")
                            logs.append(f"Found event: {attr_name} -> {func_name}")
    
            for i in range(node.child_count):
                traverse(node.child(i))
    
        traverse(root_node)
        return dependencies, logs
  • Tool description and implicit schema via type hints in function signature.
    """
    Scans code for dependencies. Supports JS, TS, HTML, Python.
    """

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yrannkv/mcp-edit-math'

If you have feedback or need assistance with the MCP directory API, please join our Discord server