Skip to main content
Glama

ida_execute_script

Execute Python scripts within IDA Pro to automate analysis tasks using IDA's API modules directly from the MCP server interface.

Instructions

Execute a Python script in IDA Pro and return its output. The script runs in IDA's context with access to all IDA API modules.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
scriptYes

Implementation Reference

  • Registration of the 'ida_execute_script' tool in the MCP server's list_tools() function, specifying name, description, and input schema.
    Tool(
        name=IDATools.EXECUTE_SCRIPT,
        description="Execute a Python script in IDA Pro and return its output. The script runs in IDA's context with access to all IDA API modules.",
        inputSchema=ExecuteScript.schema(),
    ),
  • Pydantic model defining the input schema for the 'ida_execute_script' tool, with a single 'script' string parameter.
    class ExecuteScript(BaseModel):
        script: str
  • Handler in IDAProFunctions class that sends the 'execute_script' socket request to the IDA Pro plugin and processes the response into tool output.
    def execute_script(self, script: str) -> str:
        """Execute a Python script in IDA Pro and return its output. The script runs in IDA's context with access to all IDA API modules."""
        try:
            response: Dict[str, Any] = self.communicator.send_request(
                "execute_script",
                {"script": script}
            )
            
            # Handle case where response is None
            if response is None:
                self.logger.error("Received None response from IDA when executing script")
                return "Error executing script: Received empty response from IDA"
                
            # Handle case where response contains error
            if "error" in response:
                return f"Error executing script: {response['error']}"
            
            # Handle successful execution
            success: bool = response.get("success", False)
            if not success:
                error_msg: str = response.get("error", "Unknown error")
                traceback: str = response.get("traceback", "")
                return f"Script execution failed: {error_msg}\n\nTraceback:\n{traceback}"
            
            # Get output - ensure all values are strings to avoid None errors
            stdout: str = str(response.get("stdout", ""))
            stderr: str = str(response.get("stderr", ""))
            return_value: str = str(response.get("return_value", ""))
            
            result_text: List[str] = []
            result_text.append("Script executed successfully")
            
            if return_value and return_value != "None":
                result_text.append(f"\nReturn value:\n{return_value}")
            
            if stdout:
                result_text.append(f"\nStandard output:\n{stdout}")
            
            if stderr:
                result_text.append(f"\nStandard error:\n{stderr}")
            
            return "\n".join(result_text)
            
        except Exception as e:
            self.logger.error(f"Error executing script: {str(e)}", exc_info=True)
            return f"Error executing script: {str(e)}"
  • Main MCP tool call handler in call_tool() that validates arguments and invokes the IDAProFunctions.execute_script method.
    case IDATools.EXECUTE_SCRIPT:
        try:
            if "script" not in arguments or not arguments["script"]:
                return [TextContent(
                    type="text",
                    text="Error: No script content provided"
                )]
                
            result: str = ida_functions.execute_script(arguments["script"])
            return [TextContent(
                type="text",
                text=result
            )]
        except Exception as e:
            logger.error(f"Error executing script: {str(e)}", exc_info=True)
            return [TextContent(
                type="text",
                text=f"Error executing script: {str(e)}"
            )]
  • Core implementation in IDA Pro plugin that executes the provided Python script in IDA's context using exec(), capturing stdout/stderr/return value, with UI hooks and auto-handlers to avoid interactive dialogs.
    def _execute_script_internal(self, script: str) -> Dict[str, Any]:
        """Internal implementation for execute_script without sync wrapper"""
        try:
            print(f"Executing script, length: {len(script) if script else 0}")
            
            # Check for empty script
            if not script or not script.strip():
                print("Error: Empty script provided")
                return {
                    "success": False,
                    "error": "Empty script provided",
                    "stdout": "",
                    "stderr": "",
                    "traceback": ""
                }
                
            # Create a local namespace for script execution
            script_globals = {
                '__builtins__': __builtins__,
                'idaapi': idaapi,
                'idautils': idautils,
                'idc': idc,
                'ida_funcs': ida_funcs,
                'ida_bytes': ida_bytes,
                'ida_name': ida_name,
                'ida_segment': ida_segment,
                'ida_lines': ida_lines,
                'ida_hexrays': ida_hexrays
            }
            script_locals = {}
    
            # Save original stdin/stdout/stderr
            import sys
            import io
            original_stdout = sys.stdout
            original_stderr = sys.stderr
            original_stdin = sys.stdin
    
            # Create string IO objects to capture output
            stdout_capture = io.StringIO()
            stderr_capture = io.StringIO()
            
            # Redirect stdout/stderr to capture output
            sys.stdout = stdout_capture
            sys.stderr = stderr_capture
            
            # Prevent script from trying to read from stdin
            sys.stdin = io.StringIO()
    
            try:
                # Create UI hooks 
                print("Setting up UI hooks")
                hooks = self._create_ui_hooks()
                hooks.hook()
    
                # Install auto-continue handlers for common dialogs - but first, redirect stderr
                temp_stderr = sys.stderr
                auto_handler_stderr = io.StringIO()
                sys.stderr = auto_handler_stderr
                
                print("Installing auto handlers")
                self._install_auto_handlers()
                
                # Restore stderr and save auto-handler errors separately
                sys.stderr = stderr_capture
                auto_handler_errors = auto_handler_stderr.getvalue()
                
                # Only log auto-handler errors, don't include in script output
                if auto_handler_errors:
                    print(f"Auto-handler setup errors (not shown to user): {auto_handler_errors}")
    
                # Execute the script
                print("Executing script...")
                exec(script, script_globals, script_locals)
                print("Script execution completed")
                
                # Get captured output
                stdout = stdout_capture.getvalue()
                stderr = stderr_capture.getvalue()
                
                # Filter out auto-handler messages from stdout
                stdout_lines = stdout.splitlines()
                filtered_stdout_lines = []
                
                for line in stdout_lines:
                    skip_line = False
                    auto_handler_messages = [
                        "Setting up UI hooks",
                        "Installing auto handlers",
                        "Error installing auto handlers",
                        "Found and saved",
                        "Could not access user_cancelled",
                        "Installed auto_",
                        "Auto handlers installed",
                        "Note: Could not",
                        "Restoring IO streams",
                        "Unhooking UI hooks",
                        "Restoring original handlers",
                        "Refreshing view",
                        "Original handlers restored",
                        "No original handlers"
                    ]
                    
                    for msg in auto_handler_messages:
                        if msg in line:
                            skip_line = True
                            break
                            
                    if not skip_line:
                        filtered_stdout_lines.append(line)
                
                filtered_stdout = "\n".join(filtered_stdout_lines)
                
                # Compile script results - ensure all fields are present
                result = {
                    "stdout": filtered_stdout.strip() if filtered_stdout else "",
                    "stderr": stderr.strip() if stderr else "",
                    "success": True,
                    "traceback": ""
                }
                
                # Check for return value
                if "result" in script_locals:
                    try:
                        print(f"Script returned value of type: {type(script_locals['result']).__name__}")
                        result["return_value"] = str(script_locals["result"])
                    except Exception as rv_err:
                        print(f"Error converting return value: {str(rv_err)}")
                        result["stderr"] += f"\nError converting return value: {str(rv_err)}"
                        result["return_value"] = "Error: Could not convert return value to string"
                
                print(f"Returning script result with keys: {', '.join(result.keys())}")
                return result
            except Exception as e:
                import traceback
                error_msg = str(e)
                tb = traceback.format_exc()
                print(f"Script execution error: {error_msg}")
                print(tb)
                return {
                    "success": False,
                    "stdout": stdout_capture.getvalue().strip() if stdout_capture else "",
                    "stderr": stderr_capture.getvalue().strip() if stderr_capture else "",
                    "error": error_msg,
                    "traceback": tb
                }
            finally:
                # Restore original stdin/stdout/stderr
                print("Restoring IO streams")
                sys.stdout = original_stdout
                sys.stderr = original_stderr
                sys.stdin = original_stdin
                
                # Unhook UI hooks
                print("Unhooking UI hooks")
                hooks.unhook()
                
                # Restore original handlers
                print("Restoring original handlers")
                self._restore_original_handlers()
                
                # Refresh view to show any changes made by script
                print("Refreshing view")
                self._refresh_view_internal()
        except Exception as e:
            print(f"Error in execute_script outer scope: {str(e)}")
            traceback.print_exc()
            return {
                "success": False,
                "stdout": "",
                "stderr": "",
                "error": str(e),
                "traceback": traceback.format_exc()
            }
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the script runs in IDA's context with API access, but lacks details on permissions, error handling, execution limits, or output format. For a tool that executes scripts (potentially with side effects), this is insufficient.

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

Conciseness4/5

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

The description is concise and front-loaded, using two sentences that directly state the tool's purpose and context. There's no wasted text, though it could benefit from more detail given the lack of annotations and schema coverage.

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 the complexity of script execution, no annotations, 0% schema coverage, and no output schema, the description is incomplete. It doesn't cover parameter details, behavioral traits, or return values, making it inadequate for safe and effective use by an AI agent.

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?

Schema description coverage is 0%, so the description must compensate. It mentions 'Python script' but doesn't explain the 'script' parameter's format, constraints, or examples. No additional meaning is provided beyond the basic schema, failing to address the coverage gap.

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 ('Execute a Python script') and resource ('in IDA Pro'), with the specific context of running within IDA's environment. However, it doesn't explicitly differentiate from its sibling 'ida_execute_script_from_file', which handles script execution from files rather than direct script content.

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?

No explicit guidance is provided on when to use this tool versus alternatives. The description mentions running scripts in IDA's context but doesn't specify scenarios or compare it to 'ida_execute_script_from_file' or other tools for script-related tasks, leaving usage decisions unclear.

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

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/MxIris-Reverse-Engineering/ida-mcp-server'

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