#
tokens: 7598/50000 3/3 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── ida-mcp-server.py
├── LICENSE
├── README.md
└── requirements.txt
```

# Files

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/taida957789-ida-mcp-server-plugin-badge.png)](https://mseep.ai/app/taida957789-ida-mcp-server-plugin)
  2 | 
  3 | # IDA Pro MCP Server
  4 | 
  5 | IDA Pro MCP Server is a plugin that allows remote querying and control of IDA Pro through the Model Context Protocol (MCP) interface. This plugin enables AI assistants (such as Claude) to interact directly with IDA Pro for binary analysis tasks.
  6 | 
  7 | ## Overview
  8 | 
  9 | This server provides a series of tools that allow AI assistants to perform the following operations:
 10 | - Get byte data from specific addresses
 11 | - Get disassembly code
 12 | - Get decompiled pseudocode
 13 | - Query function names
 14 | - Get segment information
 15 | - List all functions
 16 | - Find cross-references
 17 | - Get import/export tables
 18 | - Get entry points
 19 | - Define/undefine functions
 20 | - Get various data types (dword, word, byte, qword, float, double, string)
 21 | - Get all strings in the binary file
 22 | - Get the length of the instruction at the specified address
 23 | 
 24 | ## Installation
 25 | 
 26 | > **Note:** This plugin is designed for and tested with IDA Pro version 9.0+.
 27 | 
 28 | 1. Ensure Python and related dependencies are installed:
 29 | 
 30 | ```bash
 31 | pip install -r requirements.txt
 32 | ```
 33 | 
 34 | 2. Copy the `ida-mcp-server.py` file to the IDA Pro plugins directory:
 35 |    - Windows: `%Programfiles%\IDA Pro 9.0\plugins\`
 36 |    - Linux: `~/.idapro/plugins/`
 37 |    - macOS: `~/Library/Application Support/IDA Pro/plugins/`
 38 | 
 39 | ## Configure Claude / VSCode
 40 | 
 41 | Add the following configuration to the `mcp.json` file in Claude or VSCode:
 42 | 
 43 | ```json
 44 | {
 45 |   "mcpServers": {
 46 |     "IDAPro": {
 47 |       "url": "http://127.0.0.1:3000/sse",
 48 |       "type": "sse"
 49 |     }
 50 |   }
 51 | }
 52 | ```
 53 | 
 54 | ## Usage
 55 | 
 56 | 1. Open a binary file in IDA Pro
 57 | 2. The plugin will automatically load and start the MCP server locally (port 3000)
 58 | 3. Connect your AI assistant (e.g., Claude) to this server
 59 | 4. Use the AI assistant to perform binary analysis tasks
 60 | 
 61 | ## Available Analysis Tools
 62 | 
 63 | IDA Pro MCP Server provides the following tools:
 64 | 
 65 | - `get_bytes`: Get bytes at a specified address
 66 | - `get_disasm`: Get disassembly at a specified address
 67 | - `get_decompiled_func`: Get pseudocode of the function containing the specified address
 68 | - `get_function_name`: Get function name at a specified address
 69 | - `get_segments`: Get all segment information
 70 | - `get_functions`: Get all functions in the binary
 71 | - `get_xrefs_to`: Get all cross-references to a specified address
 72 | - `get_imports`: Get all imported functions
 73 | - `get_exports`: Get all exported functions
 74 | - `get_entry_point`: Get the entry point of the binary
 75 | - `make_function`: Create a function at a specified address
 76 | - `undefine_function`: Undefine a function at a specified address
 77 | - `get_dword_at`: Get the dword at a specified address
 78 | - `get_word_at`: Get the word at a specified address
 79 | - `get_byte_at`: Get the byte at a specified address
 80 | - `get_qword_at`: Get the qword at a specified address
 81 | - `get_float_at`: Get the float at a specified address
 82 | - `get_double_at`: Get the double at a specified address
 83 | - `get_string_at`: Get the string at a specified address
 84 | - `get_string_list`: Get all strings in the binary
 85 | - `get_strings`: Get all strings in the binary (with addresses)
 86 | 
 87 | ## Best Practices
 88 | 
 89 | When analyzing binary files, it's recommended to follow these steps:
 90 | 
 91 | 1. Examine the entry point
 92 | 2. Analyze the import table
 93 | 3. Review strings
 94 | 4. Track key API calls
 95 | 5. Identify main functional blocks
 96 | 6. Analyze control flow
 97 | 7. Identify malicious behaviors
 98 | 8. Analyze algorithms and encryption routines
 99 | 9. Document analysis results
100 | 10. Use advanced techniques
101 | 
102 | ## License
103 | 
104 | MIT License
105 | 
106 | Copyright (c) 2023 
107 | 
108 | Permission is hereby granted, free of charge, to any person obtaining a copy
109 | of this software and associated documentation files (the "Software"), to deal
110 | in the Software without restriction, including without limitation the rights
111 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
112 | copies of the Software, and to permit persons to whom the Software is
113 | furnished to do so, subject to the following conditions:
114 | 
115 | The above copyright notice and this permission notice shall be included in all
116 | copies or substantial portions of the Software.
117 | 
118 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
119 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
120 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
121 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
122 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
123 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
124 | SOFTWARE.
125 | 
```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
 1 | mcp==1.5.0
 2 | starlette==0.46.1
 3 | sse-starlette==2.2.1
 4 | uvicorn==0.34.0
 5 | typing_extensions==4.12.2
 6 | pydantic==2.10.6
 7 | pydantic_core==2.27.2
 8 | anyio==4.9.0
 9 | idna==3.10
10 | sniffio==1.3.1
11 | httpcore==1.0.7
12 | httpx==0.28.1
13 | httpx-sse==0.4.0
14 | h11==0.14.0
15 | click==8.1.8
16 | 
```

--------------------------------------------------------------------------------
/ida-mcp-server.py:
--------------------------------------------------------------------------------

```python
  1 | import glob
  2 | import json
  3 | import os
  4 | import ida_bytes
  5 | import ida_ua
  6 | import ida_funcs
  7 | import ida_hexrays
  8 | import ida_name
  9 | import ida_segment
 10 | import idautils
 11 | import idc
 12 | import ida_idaapi
 13 | import ida_kernwin
 14 | import idaapi
 15 | import threading
 16 | 
 17 | from typing import Dict, List, Optional, Any, Tuple
 18 | from datetime import datetime
 19 | from functools import wraps
 20 | from starlette.middleware import Middleware
 21 | from starlette.middleware.cors import CORSMiddleware
 22 | from starlette.applications import Starlette
 23 | from starlette.requests import Request
 24 | from starlette.routing import Mount, Route
 25 | from starlette.responses import Response
 26 | from mcp.server import Server
 27 | from mcp.server.sse import SseServerTransport
 28 | from mcp.server import FastMCP
 29 | import uvicorn
 30 | 
 31 | 
 32 | # Initialize FastMCP server for IDA tools
 33 | mcp = FastMCP("IDA MCP Server", port=3000)
 34 | 
 35 | # 封裝函數執行在主線程的裝飾器
 36 | def execute_on_main_thread(f):
 37 |     @wraps(f)
 38 |     def wrapper(*args, **kwargs):
 39 |         result = []
 40 |         exception = []
 41 |         
 42 |         def run_function():
 43 |             try:
 44 |                 result.append(f(*args, **kwargs))
 45 |             except Exception as e:
 46 |                 exception.append(e)
 47 |             return 0
 48 |         
 49 |         ida_kernwin.execute_sync(run_function, ida_kernwin.MFF_FAST)
 50 |         
 51 |         if exception:
 52 |             raise exception[0]
 53 |         return result[0]
 54 |     return wrapper
 55 | 
 56 | 
 57 | @mcp.tool()
 58 | @execute_on_main_thread
 59 | def get_bytes(ea: int, size: int) -> List[int]:
 60 |     """Get bytes at specified address.
 61 | 
 62 |     Args:
 63 |         ea: Effective address to read from
 64 |         size: Number of bytes to read
 65 |     """
 66 |     try:
 67 |         result = [ida_bytes.get_byte(ea + i) for i in range(size)]
 68 |         return result
 69 |     except Exception as e:
 70 |         print(f"Error in get_bytes: {str(e)}")
 71 |         return {"error": str(e)}
 72 | 
 73 | 
 74 | @mcp.tool()
 75 | @execute_on_main_thread
 76 | def get_disasm(ea: int) -> str:
 77 |     """Get disassembly at specified address.
 78 | 
 79 |     Args:
 80 |         ea: Effective address to disassemble
 81 |     """
 82 |     return idc.generate_disasm_line(ea, 0)
 83 | 
 84 | 
 85 | @mcp.tool()
 86 | @execute_on_main_thread
 87 | def get_decompiled_func(ea: int) -> Dict[str, Any]:
 88 |     """Get decompiled pseudocode of function containing address.
 89 | 
 90 |     Args:
 91 |         ea: Effective address within the function
 92 |     """
 93 |     try:
 94 |         func = ida_funcs.get_func(ea)
 95 |         if not func:
 96 |             return {"error": "No function found at address"}
 97 | 
 98 |         decompiler = ida_hexrays.decompile(func.start_ea)
 99 |         if not decompiler:
100 |             return {"error": "Failed to decompile function"}
101 | 
102 |         return {"code": str(decompiler)}
103 |     except Exception as e:
104 |         return {"error": str(e)}
105 | 
106 | 
107 | @mcp.tool()
108 | @execute_on_main_thread
109 | def get_function_name(ea: int) -> str:
110 |     """Get function name at specified address.
111 | 
112 |     Args:
113 |         ea: Effective address of the function
114 |     """
115 |     return ida_name.get_name(ea)
116 | 
117 | 
118 | @mcp.tool()
119 | @execute_on_main_thread
120 | def get_segments() -> List[Dict[str, Any]]:
121 |     """Get all segments information.
122 | 
123 |     @return: List of segments (start, end, name, class, perm, bitness, align, comb, type, sel, flags)
124 |     """
125 |     segments = []
126 |     n = 0
127 |     seg = ida_segment.getnseg(n)
128 |     while seg:
129 |         segments.append(
130 |             {
131 |                 "start": seg.start_ea,
132 |                 "end": seg.end_ea,
133 |                 "name": ida_segment.get_segm_name(seg),
134 |                 "class": ida_segment.get_segm_class(seg),
135 |                 "perm": seg.perm,
136 |                 "bitness": seg.bitness,
137 |                 "align": seg.align,
138 |                 "comb": seg.comb,
139 |                 "type": seg.type,
140 |                 "sel": seg.sel,
141 |                 "flags": seg.flags,
142 |             }
143 |         )
144 |         n += 1
145 |         seg = ida_segment.getnseg(n)
146 |     return segments
147 | 
148 | 
149 | @mcp.tool()
150 | @execute_on_main_thread
151 | def get_functions() -> List[Dict[str, Any]]:
152 |     """Get all functions in the binary."""
153 |     functions = []
154 |     for func_ea in idautils.Functions():
155 |         func_name = ida_name.get_name(func_ea)
156 |         functions.append({"address": func_ea, "name": func_name})
157 |     return functions
158 | 
159 | 
160 | @mcp.tool()
161 | @execute_on_main_thread
162 | def get_xrefs_to(ea: int) -> List[Dict[str, Any]]:
163 |     """Get all cross references to specified address.
164 | 
165 |     Args:
166 |         ea: Effective address to find references to
167 |     """
168 |     xrefs = []
169 |     for xref in idautils.XrefsTo(ea, 0):
170 |         xrefs.append({"from": xref.frm, "type": xref.type})
171 |     return xrefs
172 | 
173 | 
174 | @mcp.tool()
175 | @execute_on_main_thread
176 | def get_imports() -> dict[str, list[tuple[int, str, int]]]:
177 |     """Get all imports in the binary.
178 | 
179 |     Args:
180 |         None
181 | 
182 |     Returns:
183 |         A dictionary where the keys are module names and the values are lists of tuples.
184 |         Each tuple contains the address of the imported function, the name of the function,
185 |         and the ordinal value of the function.
186 |     """
187 |     tree = {}
188 |     nimps = idaapi.get_import_module_qty()
189 | 
190 |     for i in range(0, nimps):
191 |         name = idaapi.get_import_module_name(i)
192 |         if not name:
193 |             continue
194 |         # Create a list for imported names
195 |         items = []
196 | 
197 |         def imports_names_cb(ea, name, ord):
198 |             items.append((ea, "" if not name else name, ord))
199 |             # True -> Continue enumeration
200 |             return True
201 | 
202 |         # Enum imported entries in this module
203 |         idaapi.enum_import_names(i, imports_names_cb)
204 | 
205 |         if name not in tree:
206 |             tree[name] = []
207 |         tree[name].extend(items)
208 | 
209 |     return tree
210 | 
211 | 
212 | @mcp.tool()
213 | @execute_on_main_thread
214 | def get_exports() -> List[Tuple[int, int, int, str]]:
215 |     """Get all exports in the binary.
216 | 
217 |     @return: List of tuples (index, ordinal, ea, name)
218 |     """
219 |     return list(idautils.Entries())
220 | 
221 | 
222 | @mcp.tool()
223 | @execute_on_main_thread
224 | def get_entry_point() -> int:
225 |     """Get the entry point of the binary."""
226 |     try:
227 |         import ida_ida
228 |         return ida_ida.inf_get_start_ea()
229 |     except (ImportError, AttributeError):
230 |         try:
231 |             # Alternative method: idc.get_inf_attr to get
232 |             import idc
233 |             return idc.get_inf_attr(idc.INF_START_EA)
234 |         except (ImportError, AttributeError):
235 |             # Last alternative method: use cvar.inf
236 |             return idaapi.cvar.inf.start_ea
237 | 
238 | 
239 | @mcp.tool()
240 | @execute_on_main_thread
241 | def make_function(ea: int) -> None:
242 |     """Make a function at specified address."""
243 |     ida_funcs.add_func(ea)
244 | 
245 | 
246 | @mcp.tool()
247 | @execute_on_main_thread
248 | def undefine_function(ea: int) -> None:
249 |     """Undefine a function at specified address."""
250 |     ida_funcs.del_func(ea)
251 | 
252 | 
253 | @mcp.tool()
254 | @execute_on_main_thread
255 | def get_dword_at(ea: int) -> int:
256 |     """Get the dword at specified address."""
257 |     return idc.get_dword(ea)
258 | 
259 | 
260 | @mcp.tool()
261 | @execute_on_main_thread
262 | def get_word_at(ea: int) -> int:
263 |     """Get the word at specified address."""
264 |     return idc.get_word(ea)
265 | 
266 | 
267 | @mcp.tool()
268 | @execute_on_main_thread
269 | def get_byte_at(ea: int) -> int:
270 |     """Get the byte at specified address."""
271 |     return idc.get_byte(ea)
272 | 
273 | 
274 | @mcp.tool()
275 | @execute_on_main_thread
276 | def get_qword_at(ea: int) -> int:
277 |     """Get the qword at specified address."""
278 |     return idc.get_qword(ea)
279 | 
280 | 
281 | @mcp.tool()
282 | @execute_on_main_thread
283 | def get_float_at(ea: int) -> float:
284 |     """Get the float at specified address."""
285 |     return idc.get_float(ea)
286 | 
287 | 
288 | @mcp.tool()
289 | @execute_on_main_thread
290 | def get_double_at(ea: int) -> float:
291 |     """Get the double at specified address."""
292 |     return idc.get_double(ea)
293 | 
294 | 
295 | @mcp.tool()
296 | @execute_on_main_thread
297 | def get_string_at(ea: int) -> str:
298 |     """Get the string at specified address."""
299 |     return idc.get_strlit_contents(ea)
300 | 
301 | 
302 | @mcp.tool()
303 | @execute_on_main_thread
304 | def get_strings():
305 |     strings = []
306 |     for s in idautils.Strings():
307 |         strings.append({"address": s.ea, "string": str(s)})
308 |     return strings
309 | 
310 | @mcp.tool()
311 | @execute_on_main_thread
312 | def get_current_file_path():
313 |     return idc.get_input_file_path()
314 | 
315 | @mcp.tool()
316 | @execute_on_main_thread
317 | def list_files_with_relative_path(relative_path: str = ""):
318 |     base_dir = os.path.dirname(idc.get_input_file_path())
319 |     if  ':' in relative_path or '..' in relative_path or '//' in relative_path:
320 |         return json.dumps({"error": "Invalid relative path"})
321 |     if relative_path is None or relative_path == "":
322 |         return glob.glob(os.path.join(base_dir, "*"))
323 |     else:
324 |         return glob.glob(os.path.join(base_dir, relative_path, "*"))
325 | 
326 | @mcp.tool()
327 | @execute_on_main_thread
328 | def read_file(relative_path: str):
329 |     base_dir = os.path.dirname(idc.get_input_file_path())
330 |     if  ':' in relative_path or '..' in relative_path or '//' in relative_path:
331 |         return json.dumps({"error": "Invalid relative path"})
332 |     if relative_path is "":
333 |         return json.dumps({"error": "Relative path is required"})
334 |     with open(os.path.join(base_dir, relative_path), "r") as f:
335 |         return f.read()
336 | 
337 | @mcp.tool()
338 | @execute_on_main_thread
339 | def write_file(relative_path: str, content: str):
340 |     base_dir = os.path.dirname(idc.get_input_file_path())
341 |     if  ':' in relative_path or '..' in relative_path or '//' in relative_path:
342 |         return json.dumps({"error": "Invalid relative path"})
343 |     if relative_path is "":
344 |         return json.dumps({"error": "Relative path is required"})
345 |     with open(os.path.join(base_dir, relative_path), "w") as f:
346 |         f.write(content)
347 | 
348 | @mcp.tool()
349 | @execute_on_main_thread
350 | def read_binary(relative_path: str):
351 |     base_dir = os.path.dirname(idc.get_input_file_path())
352 |     if  ':' in relative_path or '..' in relative_path or '//' in relative_path:
353 |         return json.dumps({"error": "Invalid relative path"})
354 |     if relative_path is "":
355 |         return json.dumps({"error": "Relative path is required"})
356 |     with open(os.path.join(base_dir, relative_path), "rb") as f:
357 |         return f.read()
358 | 
359 | @mcp.tool()
360 | @execute_on_main_thread
361 | def write_binary(relative_path: str , content: bytes):
362 |     base_dir = os.path.dirname(idc.get_input_file_path())
363 |     if  ':' in relative_path or '..' in relative_path or '//' in relative_path:
364 |         return json.dumps({"error": "Invalid relative path"})
365 |     if relative_path is "":
366 |         return json.dumps({"error": "Relative path is required"})
367 |     with open(os.path.join(base_dir, relative_path), "wb") as f:
368 |         f.write(content)    
369 | 
370 | @mcp.tool()
371 | @execute_on_main_thread
372 | def eval_pythoni(script: str):
373 |     return eval(script)
374 | 
375 | @mcp.tool()
376 | @execute_on_main_thread
377 | def get_instruction_length(address: int) -> int:
378 |     """
379 |     Retrieves the length (in bytes) of the instruction at the specified address.
380 | 
381 |     Args:
382 |         address: The address of the instruction.
383 | 
384 |     Returns:
385 |         The length (in bytes) of the instruction.  Returns 0 if the instruction cannot be decoded.
386 |     """
387 |     try:
388 |         # Create an insn_t object to store instruction information.
389 |         insn = ida_ua.insn_t()
390 | 
391 |         # Decode the instruction.
392 |         length = ida_ua.decode_insn(insn, address)
393 |         if length == 0:
394 |             print(f"Failed to decode instruction at address {hex(address)}")
395 |             return 0
396 | 
397 |         return length
398 |     except Exception as e:
399 |         print(f"Error getting instruction length: {str(e)}")
400 |         return 0
401 | 
402 | @mcp.prompt()
403 | def binary_analysis_strategy() -> str:
404 |     """
405 |     Guild for analyzing the binary
406 |     """
407 |     return (
408 |         "IDA Pro MCP Server Tools and Best Practices:\n\n."
409 |         "Tools: \n"
410 |         "- get_bytes: Get bytes at specified address.\n"
411 |         "- get_disasm: Get disassembly at specified address.\n"
412 |         "- get_decompiled_func: Get decompiled pseudocode of function containing address.\n"
413 |         "- get_function_name: Get function name at specified address.\n"
414 |         "- get_segments: Get all segments information.\n"
415 |         "- get_functions: Get all functions in the binary.\n"
416 |         "- get_xrefs_to: Get all cross references to a specified address.\n"
417 |         "- get_imports: Get all imports in the binary.\n"
418 |         "- get_exports: Get all exports in the binary.\n"
419 |         "- get_entry_point: Get the entry point of the binary.\n"
420 |         "- make_function: Make a function at specified address.\n"
421 |         "- undefine_function: Undefine a function at specified address.\n"
422 |         "- get_dword_at: Get the dword at specified address.\n"
423 |         "- get_word_at: Get the word at specified address.\n"
424 |         "- get_byte_at: Get the byte at specified address.\n"
425 |         "- get_qword_at: Get the qword at specified address.\n"
426 |         "- get_float_at: Get the float at specified address.\n"
427 |         "- get_double_at: Get the double at specified address.\n"
428 |         "- get_string_at: Get the string at specified address.\n"
429 |         "- get_strings: Get all strings in the binary.\n"
430 |         "- get_current_file_path: Get the current path of the binary.\n"
431 |         "- list_files_with_relative_path: List all files in the specified relative path in the current directory.\n"
432 |         "- read_file: Read the content of a file.\n"
433 |         "- write_file: Write content to a file.\n"
434 |         "- read_binary: Read the content of a binary file.\n"
435 |         "- write_binary: Write content to a binary file.\n"
436 |         "- eval_python: Evaluate a Python script in IDA Pro.\n"
437 |         "- get_instruction_length: Get the length of the instruction at the specified address.\n"
438 |         "Best Practices: \n"
439 |         "- Initial Analysis Phase\n"
440 |         "   1. Examine the Entry Point\n"
441 |         "       - Use the get_entry_point() tool to locate the program's entry point\n"
442 |         "       - Analyze the code at the entry point to understand the program's startup flow\n"
443 |         "       - Look for unusual instructions or jumps\n"
444 |         "   2. Analyze Import Table\n"
445 |         "       - Use the get_imports() tool to view all imported functions\n"
446 |         "       - Look for suspicious API functions, such as:\n"
447 |         "           - File operations: CreateFile, WriteFile\n"
448 |         "           - Network communication: socket, connect, InternetOpen\n"
449 |         "           - Process manipulation: CreateProcess, VirtualAlloc\n"
450 |         "           - Registry operations: RegOpenKey, RegSetValue\n"
451 |         "           - Cryptography related: CryptEncrypt, CryptDecrypt\n"
452 |         "   3. Review Strings\n"
453 |         "       - Use the get_strings() tool to obtain all strings\n"
454 |         "       - Pay attention to IP addresses, URLs, domain names, file paths\n"
455 |         "       - Look for encrypted or obfuscated string patterns\n"
456 |         "       - Analyze command line parameters and error messages\n"
457 |         "   4. In-Depth Analysis Phase\n"
458 |         "       - Track Key API Calls\n"
459 |         "           - Use get_xrefs_to() to find cross-references to suspicious imported functions\n"
460 |         "           - Use get_decompiled_func() to analyze functions that call these APIs\n"
461 |         "           - Analyze how parameters and return values are handled\n"
462 |         "   5. Identify Main Functional Blocks\n"
463 |         "       - Use get_functions() to get a list of all functions\n"
464 |         "       - Sort functions by size and complexity\n"
465 |         "       - Decompile and analyze large, complex functions\n"
466 |         "       - Look for suspicious function names or unnamed functions\n"
467 |         "   6. Analyze Control Flow\n"
468 |         "       - Observe conditional branches and loop structures\n"
469 |         "       - Analyze function call graphs and execution paths\n"
470 |         "       - Look for anti-debugging and anti-VM detection techniques\n"
471 |         "       - Pay attention to unusual jumps and callback mechanisms\n"
472 |         "   7. Identifying Malicious Behaviors\n"
473 |         "       - Identify Common Malicious Functionality\n"
474 |         "           - Persistence mechanisms: Registry modifications, startup items, service creation\n"
475 |         "           - Data theft: File searching, keylogging, screen capturing\n"
476 |         "           - Communication features: C&C communication, data exfiltration channels\n"
477 |         "           - Evasion techniques: Obfuscation, packing, anti-analysis checks\n"
478 |         "           - Destructive behaviors: File encryption, system damage\n"
479 |         "   8. Analyze Algorithms and Encryption Routines\n"
480 |         "       - Identify encryption and decryption functions\n"
481 |         "       - Look for hardcoded keys and cryptographic constants\n"
482 |         "       - Analyze how data is processed in memory\n"
483 |         "   9. Analyze Network Communication\n"
484 |         "       - Identify network communication functions\n"
485 |         "       - Look for IP addresses, URLs, and domain names\n"
486 |         "       - Analyze how data is sent and received over the network\n"
487 |         "   10. Dump payloads if there is any decryption or encoding\n"
488 |         "       - Generate decryption or decodeing script in python and ida python\n"
489 |         "       - Use eval_python to execute the script in IDA Pro\n"
490 |         "       - Dump payloads in the current directory\n"
491 |         "   11. Document Analysis Results\n"
492 |         "       - Add comments to key functions\n"
493 |         "       - Rename functions to reflect their actual functionality\n"
494 |         "       - Create a logical structure diagram of the code\n"
495 |         "   12. Using Advanced Techniques\n"
496 |         "       - Use IDA Pro's advanced features like IDAPython scripting, IDA SDK, and IDA API\n"
497 |         "       - Implement custom analysis scripts to automate repetitive tasks\n"
498 |         "       - Explore IDA Pro's plugin ecosystem for additional analysis capabilities\n"
499 |     )
500 | 
501 | 
502 | def create_starlette_app(mcp_server: Server, *, debug: bool = False) -> Starlette:
503 |     """Create a Starlette application that can serve the provided mcp server with SSE."""
504 | 
505 |     middleware = [
506 |         Middleware(
507 |             CORSMiddleware,
508 |             allow_origins=["*"],
509 |             allow_methods=["*"],
510 |             allow_headers=["*"],
511 |         )
512 |     ]
513 |     return Starlette(
514 |         debug=debug,
515 |         middleware=middleware,
516 |         routes=[
517 |             Mount("/", app=mcp.sse_app()),
518 |         ],
519 |     )
520 | 
521 | 
522 | class ModelContextProtocolPlugin(ida_idaapi.plugin_t):
523 |     flags = ida_idaapi.PLUGIN_FIX | ida_idaapi.PLUGIN_HIDE
524 |     comment = "IDA Model Context Protocol Server"
525 |     help = "Provides REST API and SSE for IDA Pro analysis"
526 |     wanted_name = "IDA MCP Server"
527 |     wanted_hotkey = ""
528 | 
529 |     def init(self):
530 |         try:
531 |             print("Initializing IDA Model Context Protocol Server...")
532 |             # app = create_starlette_app(mcp, debug=True)
533 | 
534 |             def run_server():
535 |                 try:
536 |                     # 設置將異常轉換為 JSON 響應
537 |                     mcp.run(transport="sse")
538 |                     # uvicorn.run(app, host="localhost", port=3000, log_level="debug")
539 |                 except Exception as e:
540 |                     print(f"Server error: {str(e)}")
541 | 
542 |             server_thread = threading.Thread(target=run_server)
543 |             server_thread.daemon = True
544 |             server_thread.start()
545 |             print("Server started successfully!")
546 |             return ida_idaapi.PLUGIN_KEEP
547 |         except Exception as e:
548 |             print(f"Failed to start server: {str(e)}")
549 |             return ida_idaapi.PLUGIN_SKIP
550 | 
551 |     def run(self, arg):
552 |         pass
553 | 
554 |     def term(self):
555 |         print("Terminating IDA Model Context Protocol Server...")
556 | 
557 | 
558 | def PLUGIN_ENTRY():
559 |     return ModelContextProtocolPlugin()
560 | 
561 | 
562 | if __name__ == "__main__":
563 |     PLUGIN_ENTRY()
564 | 
```