Skip to main content
Glama

decode_apk

Decode APK files to access and analyze their contents using Apktool. Extract resources, source code, or customize decoding options for Android app reverse engineering.

Instructions

Decode an APK file using APKTool

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
apk_pathYes
forceNo
no_resNo
no_srcNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The primary handler function for the 'decode_apk' MCP tool. It validates input APK path, constructs the apktool decode command with options, executes it using run_command, and enriches the result with project metadata checks.
    @mcp.tool()
    async def decode_apk(
        apk_path: str,
        force: bool = True,
        no_res: bool = False,
        no_src: bool = False,
        output_dir: Optional[str] = None,
        timeout: int = DEFAULT_TIMEOUT
    ) -> Dict:
        """
        Decode an APK file using APKTool with comprehensive validation and error handling.
        
        Args:
            apk_path: Path to the APK file to decode
            force: Force delete destination directory if it exists
            no_res: Do not decode resources
            no_src: Do not decode sources
            output_dir: Custom output directory (optional)
            timeout: Command timeout in seconds
            
        Returns:
            Dictionary with operation results including validation details
        """
        # Input validation
        path_validation = ValidationUtils.validate_path(apk_path, must_exist=True)
        if not path_validation["valid"]:
            return {"success": False, "error": path_validation["error"]}
        
        if not apk_path.lower().endswith(('.apk', '.xapk')):
            return {"success": False, "error": "File must have .apk or .xapk extension"}
        
        # Determine output directory
        if output_dir is None:
            apk_name = os.path.basename(apk_path).rsplit('.', 1)[0]
            output_dir = os.path.join(WORKSPACE_DIR, apk_name)
        
        # Build command
        command = ["apktool", "d", apk_path, "-o", output_dir]
        if force:
            command.append("-f")
        if no_res:
            command.append("-r")
        if no_src:
            command.append("-s")
        
        result = run_command(command, timeout=timeout)
        
        if result["success"]:
            # Additional validation - check if output directory was created
            if os.path.exists(output_dir):
                result["output_dir"] = output_dir
                result["workspace"] = WORKSPACE_DIR
                
                # Get basic project info
                manifest_path = os.path.join(output_dir, "AndroidManifest.xml")
                apktool_yml_path = os.path.join(output_dir, "apktool.yml")
                
                result["has_manifest"] = os.path.exists(manifest_path)
                result["has_apktool_yml"] = os.path.exists(apktool_yml_path)
            else:
                result["warning"] = "Decode reported success but output directory not found"
        
        return result
  • The @mcp.tool() decorator registers the decode_apk function as an MCP tool in FastMCP framework.
    @mcp.tool()
  • Helper function used by decode_apk to execute the apktool decode command with timeout, error handling, and logging.
    def run_command(command: List[str], timeout: int = DEFAULT_TIMEOUT, cwd: Optional[str] = None) -> Dict[str, Union[str, int, bool]]:
        """Enhanced command runner with comprehensive error handling"""
        try:
            logger.info(f"Running command: {' '.join(command)}")
            
            # Input validation
            if not command or not all(isinstance(arg, str) for arg in command):
                return {
                    "success": False,
                    "error": "Invalid command format"
                }
            
            result = subprocess.run(
                command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                check=True,
                timeout=timeout,
                cwd=cwd
            )
            
            logger.info(f"Command completed successfully with return code {result.returncode}")
            return {
                "success": True,
                "stdout": result.stdout,
                "stderr": result.stderr,
                "returncode": result.returncode,
                "command": " ".join(command)
            }
            
        except subprocess.CalledProcessError as e:
            logger.error(f"Command failed with return code {e.returncode}: {e.stderr}")
            return {
                "success": False,
                "stdout": e.stdout or "",
                "stderr": e.stderr or "",
                "returncode": e.returncode,
                "error": f"Command failed with return code {e.returncode}",
                "command": " ".join(command)
            }
            
        except subprocess.TimeoutExpired as e:
            logger.error(f"Command timed out after {timeout} seconds")
            return {
                "success": False,
                "error": f"Command timed out after {timeout} seconds",
                "command": " ".join(command)
            }
            
        except FileNotFoundError:
            return {
                "success": False,
                "error": "APKTool not found. Please ensure APKTool is installed and in PATH"
            }
            
        except Exception as e:
            logger.error(f"Unexpected error running command: {str(e)}")
            return {
                "success": False,
                "error": f"Unexpected error: {str(e)}",
                "command": " ".join(command)
            }
  • Utility class providing validate_path used for input validation in decode_apk.
    class ValidationUtils:
        """Utility class for input validation"""
        
        @staticmethod
        def validate_path(path: str, must_exist: bool = True) -> Dict[str, Union[bool, str]]:
            """Validate file/directory path"""
            if not path or not isinstance(path, str):
                return {"valid": False, "error": "Path cannot be empty"}
                
            if must_exist and not os.path.exists(path):
                return {"valid": False, "error": f"Path does not exist: {path}"}
                
            return {"valid": True}
        
        @staticmethod
        def validate_class_name(class_name: str) -> Dict[str, Union[bool, str]]:
            """Validate Java class name format"""
            if not class_name or not isinstance(class_name, str):
                return {"valid": False, "error": "Class name cannot be empty"}
                
            if not class_name.replace('.', '').replace('_', '').replace('$', '').replace('/', '').isalnum():
                return {"valid": False, "error": "Invalid class name format"}
                
            return {"valid": True}
         
        @staticmethod
        def validate_search_pattern(pattern: str) -> Dict[str, Union[bool, str]]:
            """Validate search pattern"""
            if not pattern or not isinstance(pattern, str):
                return {"valid": False, "error": "Search pattern cannot be empty"}
                
            if len(pattern) > 1000:
                return {"valid": False, "error": "Search pattern too long (max 1000 characters)"}
                
            return {"valid": True}
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure but offers minimal information. It mentions the tool uses APKTool but doesn't describe what 'decode' entails (e.g., extracts resources, decompiles code, creates output directories), potential side effects, permission requirements, or error conditions. This leaves significant gaps for a tool that likely performs file system operations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise at just 6 words, with zero wasted language. Every word contributes to the core purpose statement, making it efficiently front-loaded. However, this conciseness comes at the cost of completeness for other dimensions.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a 4-parameter tool with 0% schema coverage, no annotations, but with an output schema present, the description is inadequate. While the output schema might document return values, the description doesn't address the tool's behavior, parameter meanings, or usage context sufficiently for a decoding operation that likely has significant file system implications.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage for all 4 parameters, the description provides no parameter information beyond what's implied by the tool name. It doesn't explain what 'apk_path' should contain, what 'force', 'no_res', or 'no_src' flags do, or how they affect the decoding process. The description fails to compensate for the complete lack of schema documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('decode') and target resource ('an APK file using APKTool'), providing a specific verb+resource combination. However, it doesn't explicitly differentiate from sibling tools like 'get_manifest' or 'list_resources' that might also involve APK analysis, leaving room for ambiguity about when to choose this tool over others.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. With siblings like 'get_manifest' or 'list_resources' that might provide specific APK information without full decoding, there's no indication of when full APK decoding is preferred over targeted extraction, nor any mention of prerequisites or constraints.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

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/zinja-coder/apktool-mcp-server'

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